Table of Contents

Wwise SDK 2021.1.1
Migrating to 2021.1 Authoring Plug-in API

In Wwise 2021.1, we are introducing a new API for the Authoring part of plug-ins that brings about a number of changes. This migration guide will cover those changes and provide information to help you update your plug-in code to use this new API.

Note: The new Authoring Plug-in API can be found under <Wwise>/SDK/include/AK/Wwise/Plugin.

New Features

In 2021.1, the plug-in API has been rewritten with a few goals in mind. The main goals are to provide a better default design that separates concerns between the backend and frontend implementations, to offer better support for backward compatibility and to minimize the requirements when creating a plug-in. These goals have been accomplished in the following ways:

  • The backend and frontend of a plug-in are separate entities where a backend can exist for multiple frontends. In the context of Wwise, the responsibilities of the backend have to do with model management and bank generation, while the frontend deals with the graphical user interface (GUI) and providing monitoring feedback to the user. This separation also means that only the backend portion of a plug-in needs to be instantiated in the context of a command-line session, which has a positive effect on performance. If no frontend is provided, a default one is generated at runtime.
  • The AK::Wwise::IAudioPlugin class has been split into smaller interfaces that are all versioned. Plug-ins are now able to request and provide services to the Authoring application by requesting service instances and implementing specific interfaces. Because there are fewer dependencies for typical plug-ins and the Authoring application has knowledge of the interface versions used, adapters for previous versions can be implemented to support them in future Wwise versions. Also, when interfaces are no longer supported, users can be informed of unsupported plug-ins. A consequence of this design is that plug-in makers will need to update their plug-ins less often to support newer Wwise versions.
  • The Authoring plug-in API adopted an architecture that is based on a C API and does not depend on toolset and platform-specific structures such as Windows SDK VARIANT. Plug-in dynamic libraries expose a simple C-defined structure that, for every plug-in, describes its components and provides pointers to implementations. For convenience, a C++ API reproducing the features of the original API produces these lower-level structures at compile time.
  • Registration of plug-ins has been simplified and is now embedded in the concept of a "plug-in container", which is a structure that has descriptors of all the plug-ins of a library. Plug-in classes are added to this container and the Sound Engine portion of the plug-in is automatically registered during the construction of this global container. Only a few macros are needed to expose an Authoring plug-in: this is detailed in the Library Plug-in Container section.

In addition to the aforementioned new features, some functions have been reworked for clarity.

Note: The Sound Engine part of the plug-in does not adopt the same design, retaining the approach of previous versions.

API Changes and Removals

A few methods that were deemed obsolete were removed from the API in 2021.1. Some other methods were not removed, but reworked by renaming and/or changing their arguments to make them clearer or easier to use.

Not listed are methods that have had non-optional pointer arguments changed to references.

Porting a Simple Plug-in

It is likely that your plug-in uses a subset of the features provided by the Authoring plug-in API. Each of the following sections covers the changes related to a specific feature: refer to the appropriate section based on your plug-in's usage of the API. For more advanced features of the Authoring plug-in API, refer to Common Use Cases for Requests.

Note: This section refers to pre-2021.1 as the "original" API, and to 2021.1 and up to the "new" API.

AudioPlugin

In the original API, the AK::Wwise::IAudioPlugin interface contained all the features of the Authoring plug-in API. You could simply subclass AK::Wwise::DefaultAudioPluginImplementation to empty implementations for each method, but your class still had all of these unused methods defined.

In the new API, there is a similar AK::Wwise::Plugin::AudioPlugin interface, but its only method is AK::Wwise::Plugin::AudioPlugin::GetBankParameters(). For a simple plug-in that has typical properties being written to a SoundBank, implementing this single interface is all that is needed. Implementing this interface also serves as an indicator that the implementing class is a backend class (as opposed to a frontend class, which is covered in the Implementing a Frontend section).

Concretely, there are few differences between an original and a new API class:

Original API

// MyAudioPlugin.h
class MyAudioPlugin: public AK::Wwise::DefaultAudioPluginImplementation
{
IPluginPropertySet* m_pPSet = nullptr;
public:
void Destroy() override { delete this; }
void SetPluginPropertySet(IPluginPropertySet* in_pPSet) override;
bool GetBankParameters(const GUID & in_guidPlatform, AK::Wwise::IWriteData* in_pDataWriter) const override;
};

New API

// MyAudioPlugin.h
class MyAudioPlugin : public AK::Wwise::Plugin::AudioPlugin
{
public:
const GUID& in_guidPlatform,
) const override;
};

Notice that there is only a single method left to implement: GetBankParameters. The AK::Wwise::IAudioPlugin::Destroy() function is also not necessary anymore, as instantiation and destruction is completely handled by the plug-in API. The standard C++ destructor can be use to release resources.

Using the Property Set

You may have noticed that the function AK::Wwise::IAudioPlugin::SetPluginPropertySet() has been removed in the previous section's code example. Indeed, this function is not needed anymore thanks to the AK::Wwise::Plugin::AudioPlugin interface that requests the property set component for you. By subclassing AK::Wwise::Plugin::RequestPropertySet, the AK::Wwise::Plugin::AudioPlugin interface adds a PropertySet component requirement to the plug-in description, which will be fulfilled by the Authoring application when the plug-in is instantiated. It also adds a member variable m_propertySet that will automatically be set to the PropertySet component instance at instantiation. This removes the need to manually create this member variable and implement its corresponding setter.

Implementing a simple Authoring plug-in with only GetBankParameters is therefore simplified:

Original API

// MyAudioPlugin.cpp
void MyAudioPlugin::SetPluginPropertySet(IPluginPropertySet* in_pPSet)
{
m_pPSet = in_pPSet;
}
bool MyAudioPlugin::GetBankParameters(const GUID & in_guidPlatform, AK::Wwise::IWriteData* in_pDataWriter) const
{
CComVariant varProp; m_pPSet->GetValue(in_guidPlatform, L"Placeholder", varProp);
in_pDataWriter->WriteReal32(varProp.fltVal);
return true;
}

New API

// MyAudioPlugin.cpp
bool MyAudioPlugin::GetBankParameters(const GUID& in_guidPlatform, AK::Wwise::Plugin::DataWriter& in_dataWriter) const
{
in_dataWriter.WriteReal32(m_propertySet.GetReal32(in_guidPlatform, "Placeholder"));
return true;
}

Some key differences:

  • The DataWriter argument is now a reference, as it is not optional (cannot be NULL)
  • The property set is accessed through the inherited member variable m_propertySet
  • The character string for the property name passed to the AK::Wwise::Plugin::PropertySet::GetReal32() is of type const char*, instead of LPCWSTR (const wchar_t*).
  • The type of the property (here, Real32) is specified explicitly in the method signature of the AK::Wwise::Plugin::PropertySet accessors for consistency with AK::Wwise::Plugin::DataWriter.

All of these changes make implementing this function simpler, safer and more portable.

Implementing a Frontend

Implementing AK::Wwise::Plugin::AudioPlugin provides the minimum implementation for SoundBank generation. However, providing only this part of the plug-in means there is no custom GUI to display, and so the Authoring application will generate one that looks similar to the Multi-Editor view.

As previously hinted, the AudioPlugin class represents the backend of the Authoring plug-in: it can be used in a command-line context (without a GUI) and implements any custom data or state management. To display a custom GUI, a new class needs to be created that will be attached to the same plug-in identifier. This class will be instantiated separately from the backend class.

The frontend class is implemented by subclassing a frontend interface. Due to the nature of GUIs, these are permitted to be platform specific. Hence, the AK::Wwise::Plugin::GUIWindows interface, to which the original frontend-related methods were moved, can be subclass for providing a custom plug-in GUI on Windows.

class MyFrontend : public AK::Wwise::Plugin::GUIWindows
{
public:
bool GetDialog(
uint32_t& out_uiDialogID,
PopulateTableItem*& out_pTable
) const;
bool WindowProc(
HWND in_hWnd,
uint32_t in_message,
WPARAM in_wParam,
LPARAM in_lParam,
LRESULT& out_lResult
);
bool Help(
HWND in_hWnd,
const char* in_szLanguageCode
);
};
Note: If you intend to use MFC, you should also subclass AK::Wwise::Plugin::PluginMFCWindows first. This will handle the initialization of a global CWinApp for your library.

In a frontend class, you must not subclass AK::Wwise::Plugin::AudioPlugin or implement any backend related logic, such as property value adjustments or operations affecting the result of a SoundBank generation. The frontend should be solely responsible for displaying properties and monitoring data in a user-friendly way, and update the plug-in model based on user input.

If the backend does not need to make any adjustments to values supplied by the user, the frontend can simply request the PropertySet component by subclassing AK::Wwise::Plugin::RequestPropertySet. However, if the backend does any value adjustments on properties, for example to implement dynamic property ranges, this should be implemented in the backend.

If the backend offers some implementations that the frontend requires, it can request theLinkBackend service by subclassing AK::Wwise::Plugin::RequestLinkBackend. It will provide the frontend class with a m_backend instance representing the backend instance to which it is bound.

The reverse is also possible, where a backend class can request LinkFrontend by subclassing AK::Wwise::Plugin::RequestLinkFrontend. One big difference for LinkFrontend is that there can be multiple frontends for one backend: the m_frontend instance inherited therefore represents an array of frontends. The size of the array can be obtained by the GetArray method and a ForEach function is offered for convenience.

Common Use Cases for Requests

While the PropertySet component request is made implicitly by the AK::Wwise::Plugin::AudioPlugin interface because it is typically needed in the context of AK::Wwise::Plugin::AudioPlugin::GetBankParameters(), other components and services are optional and can be requested manually by subclassing any of the available AK::Wwise::Plugin::Request[...] classes (refer to Request Components and Services). When the plug-in provides an implementation to the Authoring application, the interface is not prefixed by Request. For example, this is the case for AK::Wwise::Plugin::Source, AK::Wwise::Plugin::SinkDevices and AK::Wwise::Plugin::PropertyDisplayName.

The following is a list of common use cases in the original API and the corresponding services that need to be requested to obtain the same features in the new API.

Monitoring Data

Monitoring data sent by the Sound Engine counter-part of the plug-in is received through the NotifyMonitorData method. This method has been moved to a notification interface. Subclass AK::Wwise::Plugin::Notifications::Monitor to implement this method.

Refer to Monitoring in Authoring for details on implementing the AK::Wwise::Plugin::Notifications::Monitor interface.

Plug-in License

In the original API, to provide a custom handler for licensing you had to implement AK::Wwise::IAudioPlugin::GetLicenseStatus. This function has been moved to a separate interface: subclass AK::Wwise::Plugin::License to implement this method.

Refer to Managing Licenses for details on how to implement AK::Wwise::Plugin::License.

Object Media and Media Converter

Plug-in data meant to be handled as media, typically audio files that can be encoded during a source conversion process, could be supported by implementing AK::Wwise::IAudioPlugin::SetPluginObjectMedia() and AK::Wwise::IAudioPlugin::GetPluginMediaConverterInterface(). These, along with the management of media objects, have been centralized in the AK::Wwise::Plugin::ObjectMedia. Object media methods are implemented directly inside the plug-in class. The media converter, which is still optional, is a separate interface to implement: AK::Wwise::Plugin::MediaConverter.

Refer to Adding Media to an Audio Plug-in for details on how to use these interfaces.

Custom Plug-in Data

All plug-in data that are not managed through the PropertySet or ObjectMedia components have been centralized in a common interface AK::Wwise::Plugin::CustomData. While most methods are the same, CopyInto has been reworked to reverse its logic.

The three Init functions are mutually exclusive: one of them will be called when the plug-in is initialized depending on the context where it is loaded.

Subclass the AK::Wwise::Plugin::CustomData interface to implement these methods. Refer to Providing Custom Data for details on how to implement the CustomData interface.

Note: AK::Wwise::Plugin::CustomData::InitFromInstance() initializes its instance from its argument, as opposed to initializing the provided instance in the original API through AK::Wwise::IAudioPlugin::CopyInto().

Make sure to apply this logic reversal when porting a plug-in using Custom Data to the 2021.1 Authoring Plug-in API.

virtual void Destroy()=0
Interface used to write data during sound bank generation.
Definition: HostDataWriter.h:246
virtual bool GetDialog(eDialog in_eDialog, uint32_t &out_uiDialogID, PopulateTableItem *&out_pTable) const
Retrieves the plug-in dialog parameters.
Definition: GUIWindows.h:281
virtual bool GetBankParameters(const GUID &in_guidPlatform, IWriteData *in_pDataWriter) const
Definition: AudioPlugin.h:637
bool WriteReal32(float in_value)
Writes a 32-bit, single-precision floating point value.
Definition: HostDataWriter.h:428
virtual bool Help(HWND in_hWnd, eDialog in_eDialog, const char *in_szLanguageCode) const
Called when the user clicks on the '?' icon.
Definition: GUIWindows.h:324
Use this base class to quickly implement most plugin functions empty.
Definition: AudioPlugin.h:621
Windows frontend plug-in API for Audio plug-ins.
Definition: GUIWindows.h:201
Wwise API for general Audio Plug-in's backend.
Definition: AudioPlugin.h:134
virtual bool WindowProc(eDialog in_eDialog, HWND in_hWnd, uint32_t in_message, WPARAM in_wParam, LPARAM in_lParam, LRESULT &out_lResult)
Window message handler for dialogs.
Definition: GUIWindows.h:304
virtual void SetPluginPropertySet(IPluginPropertySet *in_pPSet)
Definition: AudioPlugin.h:623
virtual bool GetBankParameters(const GUID &in_guidPlatform, DataWriter &in_dataWriter) const
Obtains parameters that will be written to a bank.
Definition: AudioPlugin.h:229
virtual bool WriteReal32(float in_fReal32)=0
Definition: PluginHelpers.h:46