Introduction to Wwise and Custom Plugin Development

Wwise (Wave Works Interactive Sound Engine) by Audiokinetic is one of the most widely used audio middleware solutions in the game and interactive media industries. It provides a comprehensive toolset for sound designers and audio programmers to manage, mix, and implement audio assets in real time. While the standard Wwise suite includes a robust library of built-in effects (reverbs, delays, compressors, etc.) and source plugins, many projects demand unique sound processing that goes beyond these defaults. Creating custom Wwise plugins allows you to extend the engine’s capabilities with tailored audio algorithms — whether you need a specialized distortion effect for a sci-fi weapon, a custom spatialization algorithm for VR, or a real-time granular synthesizer that responds to gameplay variables. This article walks through the entire process of building a custom Wwise plugin, from understanding the architecture to packaging and distribution, focusing on practical steps and advanced best practices.

The demand for bespoke audio processing in games and interactive experiences has grown significantly. Modern players expect immersive soundscapes that react dynamically to every in-game event. Off-the-shelf effects often fall short when trying to achieve a signature sound for your project. By diving into Wwise plugin development, you gain control over every aspect of the audio pipeline — from sample-level processing to high-level parameter modulation via RTPCs. This guide assumes you have a working knowledge of C++ and digital audio concepts but explains each stage in enough detail to get you started from scratch.

Understanding Wwise Plugin Architecture

Before diving into code, it is essential to understand the structure of a Wwise plugin. Plugins are dynamic link libraries (DLLs) that interface with Wwise through the Wwise SDK. The SDK provides base classes and interfaces that you must implement to create effect (FX) plugins, source plugins, or processing plugins. The architecture consists of three main layers:

  • Plugin Interface: The main entry point that registers the plugin with Wwise, defines its parameters, and provides the factory function to create instances.
  • Processing Engine: The core where your DSP algorithm lives. This is typically implemented in a class that inherits from AK::IAkPlugin and implements the Process method, which is called for each audio buffer.
  • GUI (Wwise Authoring): If your plugin has configurable parameters, you can build a custom UI using the Wwise plugin framework. This part uses the authoring API to present controls like sliders, drop-downs, and graphs in the Wwise Project Editor.

Plugins can be effect plugins (process audio input and produce output), source plugins (generate audio from scratch, like a synthesizer), or metasound plugins (envelopes, LFOs, etc.). The development approach is similar for all types, but the base classes differ slightly. We will focus on effect plugins as the most common use case.

Key Components of the Wwise SDK

The Wwise SDK is available for download from the Audiokinetic website. It includes header files, static libraries, sample projects, and documentation. The essential files you'll work with include:

  • AK/Plugin/PluginServices.h – Helper classes for parameter management.
  • AK/Plugin/PluginBase.h – Base plugin interface.
  • AK/Plugin/NumericalParam.h – Parameter handling using numerical ID.
  • AK/WwiseAuthoringAPI/... – For building custom GUI (optional).

You can read the official Wwise SDK Documentation for detailed API references. Additionally, Audiokinetic provides sample plugins (e.g., "SampleFX" and "SampleSource") that serve as excellent starting points.

Prerequisites for Custom Plugin Development

To successfully build a custom Wwise plugin, you need a specific set of skills and tools. While the original article lists the basics, here is an expanded, practical checklist:

  • C++ Proficiency: You must be comfortable with modern C++ (at least C++14), including memory management, real-time audio buffer handling, and debugging. Knowledge of DSP (digital signal processing) is highly beneficial but can be learned alongside.
  • Wwise SDK Familiarity: Download the latest version of the Wwise SDK (matching your Wwise version). Spend time reviewing the documentation and sample code before starting your own plugin.
  • Visual Studio: Windows development typically uses Microsoft Visual Studio 2019 or 2022. The Wwise plugin templates integrate directly into the IDE. For macOS, Xcode is supported but less common for Wwise plugin development.
  • Development Environment Setup: You need to correctly configure include directories, library paths, and preprocessor definitions. The SDK provides a CMake-based build system, but Visual Studio solutions can also be manually configured.
  • Audiokinetic Account: A free account gives you access to the SDK downloads, documentation, and community forums where you can ask questions.
  • Wwise Launcher: Use the Wwise Launcher to manage Wwise versions and SDKs. It can also help create a new plugin project from a template (available in newer versions).

Don’t overlook the importance of a solid testing setup — you’ll need a Wwise project where you can load your plugin and test it in real time with a game or standalone simulation.

  • Understanding of audio formats (PCM, floats, sample rate conversion).
  • Knowledge of the game engine integration (Unity, Unreal Engine) to understand how plugins interact with the host.
  • Experience with version control (Git) to manage plugin code across projects.
  • Basic understanding of SIMD programming (SSE, AVX) for performance optimization on modern CPUs.

Step-by-Step: Creating a Custom Wwise Plugin

Below is an in-depth walkthrough for building a simple effect plugin — a custom low-pass filter with a resonance control that uses a second-order IIR filter. This will illustrate the general workflow that applies to any plugin type.

Step 1: Set Up the Development Environment

First, install the Wwise SDK. From the Wwise Launcher, go to the "SDKs" tab and download the version that matches your Wwise installation (e.g., 2022.1.x). Unzip the SDK to a location of your choice, such as C:\WWiseSDK. Then open Visual Studio and create a new project. To save time, download the official Wwise Plugin Template from Audiokinetic's website (look for "Wwise Plugin Tools" or "Wwise Plugin Templates").

If using the template, run the CreatePlugin.bat script and follow the prompts to generate a Visual Studio solution with the correct structure. If building from scratch, you need to manually set up include directories for %WWISESDK%\include and the appropriate library paths for %WWISESDK%\lib\vc160 (or vc140, etc.) for both Debug and Release configurations. Ensure you set the correct runtime library: use Multi-threaded DLL (/MD) for Release builds to match Wwise's own binaries.

Step 2: Create the Plugin Class

Your main plugin class should inherit from AK::IAkEffectPlugin (for FX plugins). You must implement the following pure virtual methods:

class CustomLowPass : public AK::IAkEffectPlugin
{
public:
    AKRESULT Init(AK::IAkPluginMemAlloc *in_pAllocator, 
                  AK::IAkEffectPluginContext *in_pContext, 
                  AK::IAkPluginParam *in_pParams, 
                  AkAudioFormat &in_rFormat) override;
    AKRESULT Term(AK::IAkPluginMemAlloc *in_pAllocator) override;
    AKRESULT Reset() override;
    AKRESULT GetPluginInfo(AkPluginInfo &out_rPluginInfo) override;
    void Process(AkAudioBuffer *in_pBuffer) override;
};

In the Init method, you cast the in_pParams pointer to your custom parameter class (see Step 3) and allocate any internal state (filter coefficients, delay lines). The Process method is where the actual DSP happens — it iterates over the audio buffer's channels and samples, applies your algorithm, and writes the output back into the same buffer (or a new one if specified).

Pay close attention to the buffer format: AkAudioBuffer contains interleaved or deinterleaved data depending on configuration. The GetChannel method returns a pointer to the start of a channel's sample data. Ensure your algorithm handles both mono and multi-channel (up to 7.1) without channel crosstalk.

Step 3: Define Parameters

Parameters are controlled via a separate class that inherits from AK::IAkPluginParam. You define a set of parameter IDs (enum) and then implement SetParam and GetParam to allow Wwise to read/write values. For the low-pass filter, we need two parameters:

  • Cutoff Frequency (float, range 20 Hz – 20 kHz, default 1 kHz)
  • Resonance (float, range 0.0 – 1.0, default 0.707)

Here’s a simplified parameter class snippet:

enum CustomLowPassParams
{
    PARAM_CUTOFF = 0,
    PARAM_RESONANCE,
    NUM_PARAMS
};

class CustomLowPassParams : public AK::IAkPluginParam
{
public:
    CustomLowPassParams();
    virtual ~CustomLowPassParams();
    virtual IAkPluginParam *Clone(AK::IAkPluginMemAlloc *in_pAllocator);
    virtual AKRESULT SetParam(AkPluginParamID in_id, AkReal32 in_fValue);
    virtual AKRESULT GetParam(AkPluginParamID in_id, AkReal32 &out_fValue);
    // ... other required methods
private:
    AkReal32 m_fCutoff;
    AkReal32 m_fResonance;
};

In the Process method, you read these parameters and update the filter coefficients accordingly. To prevent parameter changes from causing clicks, apply smoothing (e.g., linear interpolation over a few samples). A common technique is to maintain a smoothed value that moves toward the target over a configurable ramp time (typically 5–10 ms).

Step 4: Implement the DSP Algorithm

For a second-order low-pass IIR filter, the standard direct form 1 implementation works well. Keep in mind that real-time audio demands low-latency code: avoid dynamic allocations, use static arrays for delay lines, and prefer integer math when appropriate. Here is a skeletal process function:

void CustomLowPass::Process(AkAudioBuffer *in_pBuffer)
{
    AkUInt16 numChannels = in_pBuffer->NumChannels();
    AkUInt16 numFrames = in_pBuffer->MaxFrames();
    for (AkUInt16 ch = 0; ch < numChannels; ++ch)
    {
        AkReal32 *pBuf = in_pBuffer->GetChannel(ch);
        for (AkUInt16 i = 0; i < numFrames; ++i)
        {
            // Read parameter-smoothed coefficients (computed in UpdateFilter state)
            // Apply filter: y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] - a1*y[n-1] - a2*y[n-2]
            pBuf[i] = ...;
            // Update delay line
        }
    }
}

Remember to handle edge cases such as very low sample rates (upsampling might be needed for cutoff frequencies above Nyquist) and to reset filter states when the plugin is reset or parameters change discontinuously. Use a state variable filter (SVF) if you need fast modulation without artifacts.

Step 5: Register and Compile the Plugin

Each plugin must be registered with Wwise's plugin manager. In your plugin’s source file, add the registration macro:

AK::IAkPlugin* CreateCustomLowPass(AK::IAkPluginMemAlloc *in_pAllocator)
{
    return AK::PluginRegistration::InstantiatePlugin<CustomLowPass>(in_pAllocator);
}
// Then use a plugin definition macro, e.g.:
AK_IMPLEMENT_PLUGIN_FACTORY(CustomLowPass, AkPluginTypeEffect, CustomLowPassConfig::TAudioPlugin::PluginID)

Compile the project as a DLL (Release configuration). Ensure the output binary is placed in the correct directories for Wwise authoring (e.g., %WWISEROOT%\Authoring\x64\Release\bin\plugins) and for the runtime (e.g., %WWISEROOT%\SDK\Win64\Release\bin\plugins). If you are building for multiple platforms, create separate configurations.

Step 6: Test Inside Wwise

Launch Wwise Authoring (the Wwise Project Editor). Create a new Audio Bus or insert a sound effect. In the Effect tab, you should see your plugin listed under "Custom." Add it to the signal chain. Adjust the parameters in the property editor. If you built a custom GUI, it will appear. Play audio to verify the processing. Use the Profiler to check CPU usage and memory. It is also wise to test the plugin in a live game integration (e.g., Unity) to ensure it works under real-world conditions with sound prioritization and spatialization.

Best Practices for Robust Plugin Development

The original article listed several good practices. Here we expand each with concrete reasoning and additional advice.

Optimize for Low Latency and High Performance

  • Use fixed-point arithmetic where possible to avoid floating-point pipeline stalls on mobile CPUs.
  • Precompute coefficients and only update them when parameters change (e.g., track a dirty flag). This avoids redundant math inside the sample loop.
  • Use SSE/AVX intrinsics for SIMD processing on bulk sample loops to gain 2-4x speed on modern x86 CPUs.
  • Test with extreme parameter values (cutoff at Nyquist, resonance near self-oscillation) to ensure no denormals or infinite loops occur. Enable flush-to-zero mode for denormal numbers.

Ensure Compatibility Across Wwise Versions

  • Stay updated with the Wwise SDK release notes. Each major version introduces new features and deprecates old ones.
  • Link against the correct runtime libraries (MD for multi-threaded DLL). Mismatched runtimes cause crashes.
  • If you distribute your plugin, provide separate DLLs for each Wwise version (e.g., 2021.1, 2022.1). Use the AK::WwiseAuthoringAPI::GetPluginVersion to warn users if mismatch is detected.

Document Your Code Thoroughly

  • In addition to inline comments, write a README that explains the algorithm, parameter ranges, and how to integrate the plugin into a game engine.
  • Include examples of Wwise project configurations where the plugin excels.
  • Use Doxygen-style comments for header files so users can generate documentation.

Test Extensively in Different Sound Environments

  • Test with mono, stereo, and multi-channel inputs (5.1, 7.1). Many plugins break on multi-channel due to channel-specific state not being separated.
  • Simulate parameter automation at high rates (e.g., MIDI CC messages) to ensure no audio glitches.
  • Run the Wwise Profiler while stressing the plugin with many instances (up to 64).

Additional Best Practices

  • Implement Preset Management — Wwise supports saving and loading presets. Ensure your plugin correctly serializes/deserializes its parameters using ReadParamBlock and WriteParamBlock.
  • Handle Bypass elegantly. When bypassed, the plugin should pass the audio through unmodified with minimal overhead. Check in_pBuffer->eState in Process.
  • Provide Debugging Helpers: use AKPLATFORM::OutputDebugMsg to log warnings (e.g., when parameters are out of range) but disable them in release builds.

Advanced Topics: Extending Custom Plugins

Building a Custom GUI

For a professional feel, you can create a UI that appears in the Wwise Authoring environment. This involves building a separate UI plugin DLL that communicates with your processing DLL via the AK::WwiseAuthoringAPI::IAkUIPlugin interface. You can use the Wwise UI framework or integrate standard Windows controls (Direct2D, WinForms) via a bridge. The Wwise Authoring API Documentation provides examples for sliders, knobs, and graphs.

Real-Time Parameter Modulation

Wwise allows game parameters to modulate plugin parameters via RTPCs (real-time parameter controls). In your plugin, you must expose parameter IDs and ensure they can be updated per-buffer without reinitialization. This is particularly powerful: you can map a game variable (e.g., player health) to the filter cutoff for audio-driven feedback. Implement the SetParam method to accept values at any time, and apply smoothing to avoid zipper noise.

Multi-Platform Support

Your custom plugin may need to run on PC, consoles (PS5, Xbox), and mobile. The Wwise SDK is platform-specific. You will need to cross-compile your code for each target, handling endianness, memory alignment, and platform-specific compiler intrinsics. Use preprocessor macros (#if defined(_WIN32) || defined(PS5)...) to isolate platform code. Audiokinetic provides platform abstraction helpers in AK/SoundEngine/Platforms/.... Test on each target early to catch alignment issues.

Designing for Real-Time Performance

Performance is critical in Wwise plugins because they run inside the audio rendering thread. Any delay or spike can cause audible glitches. Here are specific techniques to keep your plugin efficient:

  • Memory Allocation: Allocate all memory during Init and never in Process. Use the provided allocator (in_pAllocator) for all plugin-related allocations.
  • Branchless Code: Avoid conditional branches inside sample loops. Use arithmetic tricks (e.g., clamp with min/max) or look-up tables instead of if-statements.
  • Constant Folding: Compute all coefficients that depend on sample rate and fixed parameters once in Init and only update them when parameters change.
  • Cache Locality: Store filter states in contiguous arrays per channel to maximize cache hits. Avoid pointer chasing.

Distributing Your Plugin

Once your plugin is stable, you can package it for distribution. The standard method is to create a Wwise Plugin Package (installer). Use the Wwise Plugin Installer tool from the SDK (or a custom installer) that places the DLLs in the correct folders. Create a manifest file that lists the plugin ID, version, and supported Wwise versions. You can sell or give away your plugin on marketplaces like the Audiokinetic Community or third-party audio plugin stores. Provide clear installation instructions and a license agreement. Consider offering both a free trial (with limitations) and a full paid version.

Real-World Example: Custom Granular Source Plugin

To illustrate the power of custom plugins, consider a source plugin that generates granular clouds from recorded samples. This plugin could load a small audio clip and use random playback positions, grain sizes, and pitches to create evolving textures. In a game, this could be used for ambient wind, magical spells, or dynamic music transitions. Building this requires a source plugin (inheriting from AK::IAkSourcePlugin), a parameter set for grain rate, density, and randomization, and careful memory management to avoid popping at grain boundaries. Such a plugin is not available in stock Wwise and can set a game's audio apart. Key implementation details include a circular buffer for overlapping grains, envelope shaping (Hann or rising sawtooth), and seeded random number generation for reproducibility in sync with the game engine.

Troubleshooting Common Issues

  • Plugin not appearing in Wwise: Check that the DLL is built for the correct platform (x64) and placed in the correct folder. Verify the plugin ID in the registration macro matches the ID in the Wwise project. Also ensure the plugin is compiled with the correct C++ exception handling settings (disable C++ exceptions).
  • Audio distortion or crashes: Enable AK_FLOAT_CAUSES_NAN debugging in development. Likely causes: uninitialized filter state, buffer overrun, or division by zero. Use the Wwise Profiler to detect high CPU usage.
  • Parameter updates cause clicks: Apply ramping (over 5-10 ms) when coefficients change. Use a state variable filter to handle fast modulation smoothly. Ensure the ramp length is consistent across sample rates.
  • Memory leaks: Always release allocated memory in Term using the same allocator (in_pAllocator->Free). Never use standard new/delete. Use RAII wrappers for automatic cleanup.
  • Plugin works in Wwise Authoring but not in game: The runtime plugin DLL must be present in the game's executable directory or the appropriate platform-specific folder. Also verify that the plugin's binary is compiled for the same architecture (x86 vs x64) as the game.

Conclusion

Creating custom Wwise plugins opens endless possibilities for sound designers and audio programmers. The ability to implement specialized DSP algorithms, generate unique source material, and tightly integrate with game logic gives your audio a distinctive edge. While the journey from concept to a production-ready plugin requires disciplined coding, thorough testing, and familiarity with the Wwise SDK, the results are well worth the effort. Start with simple effect plugins and gradually tackle more complex source plugins or multimodal processors. The Audiokinetic Community Forums are a valuable resource for troubleshooting and sharing ideas. With the guidance provided in this article, you are ready to build audio processing that is truly unique to your project.