AAX SDK  2.4.1
Avid Audio Extensions Development Kit
Classes | Functions
Description callback

Static configuration for an AAX plug-in.

On this page

About the Describe callback and AAX descriptor interfaces

In Describe, a plug-in declares its static (or default) configuration and any properties that the host will need in order to manage the plug-in.
A plug-in's Describe callback ties the Algorithm, GUI, and Data Model together. In this callback, the plug-in provides a description of its algorithm callbacks, data connections, and other static plug-in properties using a set of host-provided description interfaces. The plug-in uses a tiered hierarchy of these description interfaces to complete its description:
The actual description callback entrypoint is ACFRegisterPlugin(), which is declared in AAX_Exports.cpp. This method is implemented inside of the AAX Library, where it calls the plug-in's custom implementation of the GetEffectDescriptions() callback.
// ***************************************************************************
// ROUTINE: GetEffectDescriptions
// ***************************************************************************
{
AAX_IEffectDescriptor * plugInDescriptor = outCollection->NewDescriptor();
if ( plugInDescriptor )
{
result = DemoGain_GetPlugInDescription( plugInDescriptor );
if ( result == AAX_SUCCESS )
outCollection->AddEffect( kEffectID_DemoGain, plugInDescriptor );
}
else result = AAX_ERROR_NULL_OBJECT;
outCollection->SetManufacturerName( "Avid, Inc." );
outCollection->AddPackageName( "DemoGain Plug-In" );
outCollection->AddPackageName( "DemoGain" );
outCollection->AddPackageName( "DmGi" );
outCollection->SetPackageVersion( 1 );
return result;
}
int32_t AAX_Result
Definition: AAX.h:337
@ AAX_ERROR_NULL_OBJECT
Definition: AAX_Errors.h:44
@ AAX_SUCCESS
Definition: AAX_Errors.h:39
AAX_Result GetEffectDescriptions(AAX_ICollection *inCollection)
The plug-in's static Description entrypoint.
Interface to represent a plug-in binary's static description.
Definition: AAX_ICollection.h:54
virtual AAX_Result SetPackageVersion(uint32_t inVersion)=0
Set the plug-in package version number.
virtual AAX_Result AddEffect(const char *inEffectID, AAX_IEffectDescriptor *inEffectDescriptor)=0
Add an Effect description to the collection.
virtual AAX_Result SetManufacturerName(const char *inPackageName)=0
Set the plug-in manufacturer name.
virtual AAX_Result AddPackageName(const char *inPackageName)=0
Set the plug-in package name.
virtual AAX_IEffectDescriptor * NewDescriptor()=0
Create a new Effect descriptor.
Description interface for an effect's (plug-in type's) components.
Definition: AAX_IEffectDescriptor.h:50
GetEffectDescriptions() from the DemoGain example plug-in
In general, the following procedure is used when describing an AAX plug-in:
  1. Create an Effect description interface from the Collection interface provided by the host
  2. Use the Effect description interface to create references to one or more component description interfaces.
  3. Describe each algorithm component by populating the component descriptions.
  4. Add the components to the Effect description
  5. Add additional modules and properties to the Effect description.
  6. Add the completed Effect to the Collection
  7. Repeat for any additional Effects included in the plug-in binary.
  8. Return the completed Collection interface to the host and exit.
Note
The host owns all memory associated with any descriptors that the plug-in returns via this callback.

Top level: Collection

The AAX_ICollection interface provides a creation function (AAX_ICollection::NewDescriptor()) for new plug-in descriptors, which in turn provides access to the various interfaces necessary for describing a plug-in (see the DemoGain_GetPlugInDescription() and DescribeAlgorithmComponent() listings below).
When a plug-in description is complete, it is added to the collection via the AAX_ICollection::AddEffect() method. The AAX_ICollection interface also provides some additional description methods that are used to describe the overall plug-in package. These methods can be used to describe the plug-in package's name, the name of the plug-in's manufacturer, and the plug-in package version. Once these have been described, the completed description interface is returned to the host and exits.
// ***************************************************************************
// ROUTINE: GetEffectDescriptions
// ***************************************************************************
{
.
.
.
AAX_IEffectDescriptor * plugInDescriptor = outCollection->NewDescriptor();
.
.
.
result = DemoGain_GetPlugInDescription( plugInDescriptor );
.
.
.
outCollection->AddEffect( kEffectID_DemoGain, plugInDescriptor );
.
.
.
outCollection->SetManufacturerName( "Avid, Inc." );
outCollection->AddPackageName( "DemoGain Plug-In" );
outCollection->AddPackageName( "DemoGain" );
outCollection->AddPackageName( "DmGi" );
outCollection->SetPackageVersion( 1 );
.
.
.
return result;
}
Populating the AAX_ICollection interface

Middle level: Effects

The AAX_IEffectDescriptor interface provides description methods that are used to describe the Effect, such as its name, category, associated page table, and, importantly, creation methods for its data model, GUI, and other AAX modules.
// ***************************************************************************
// ROUTINE: DemoGain_GetPlugInDescription
// ***************************************************************************
static AAX_Result DemoGain_GetPlugInDescription( AAX_IEffectDescriptor * outDescriptor )
{
int err;
AAX_IComponentDescriptor * compDesc = outDescriptor->NewComponentDescriptor ();
if ( !compDesc )
// Add empty component descriptors to the host, register a processing
// entrypoint for each, and populate with description information.
//
// Alg component
DescribeAlgorithmComponent( compDesc );
err = outDescriptor->AddComponent( compDesc ); AAX_ASSERT (err == 0);
outDescriptor->AddPlugInName ( "Demo Gain AAX" );
outDescriptor->AddPlugInName ( "Demo Gain" );
outDescriptor->AddPlugInName ( "DemoGain" );
outDescriptor->AddPlugInName ( "DmGain" );
outDescriptor->AddPlugInName ( "DGpr" );
outDescriptor->AddPlugInName ( "Dn" );
outDescriptor->AddPlugInCategory ( AAX_ePlugInCategory_Dynamics );
outDescriptor->AddProcPtr( (void *) DemoGain_Parameters::Create, kAAX_ProcPtrID_Create_EffectParameters );
outDescriptor->AddResourceInfo ( AAX_eResourceType_PageTable, "DemoGainPages.xml" );
#if PLUGGUI != 0
outDescriptor->AddProcPtr( (void *) DemoGain_GUI::Create, kAAX_ProcPtrID_Create_EffectGUI );
#endif
return AAX_SUCCESS;
}
#define AAX_ASSERT(condition)
Asserts that a condition is true and logs an error if the condition is false.
Definition: AAX_Assert.h:268
@ kAAX_ProcPtrID_Create_EffectGUI
AAX_IEffectGUI creation procedure
Definition: AAX_Callbacks.h:36
@ kAAX_ProcPtrID_Create_EffectParameters
AAX_IEffectParameters creation procedure
Definition: AAX_Callbacks.h:35
@ AAX_eResourceType_PageTable
Definition: AAX_Enums.h:434
@ AAX_ePlugInCategory_Dynamics
Compressor, expander, limiter, etc.
Definition: AAX_Enums.h:289
Description interface for an AAX plug-in component.
Definition: AAX_IComponentDescriptor.h:47
virtual AAX_IComponentDescriptor * NewComponentDescriptor()=0
Create an instance of a component descriptor.
virtual AAX_Result AddResourceInfo(AAX_EResourceType inResourceType, const char *inInfo)=0
Set resource file info.
virtual AAX_Result AddProcPtr(void *inProcPtr, AAX_CProcPtrID inProcID)=0
Add a process pointer.
virtual AAX_Result AddComponent(AAX_IComponentDescriptor *inComponentDescriptor)=0
Add a component to an instance of a component descriptor.
Populating an AAX_IEffectDescriptor interface
All components in an Effect must share the same AAX modules; for example, it is not possible to use one data model definition for one sample rate and another data model definition for a different sample rate. Therefore, a plug-in's AAX modules are defined in its Effect description.

Registering multiple Effects

A single plug-in package may include multiple Effects, which are added in turn in the description method. Once these connections are made, Describe passes the host a populated description interface and returns.
For example, consider an EQ plug-in that contains both one-band and four-band variations, each of which the user should see as a distinct plug-in. These Effects would be described and added separately to the collection object and would appear as separate products to the user.
AAX_Result GetEffectsDescriptions ( AAX_ICollection * outCollection )
{
if ( result == AAX_SUCCESS )
{
AAX_IEffectDescriptor * aDesc1 = outCollection -> NewDescriptor ();
// ...
// Populate aDesc1 with one - band EQ description
// ...
result = outCollection -> AddEffect ( kEffectID_MyOneBandEQ , aDesc1 );
}
if ( result == AAX_SUCCESS )
{
AAX_IEffectDescriptor * aDesc4 = outCollection -> NewDescriptor ();
// ...
// Populate aDesc4 with four - band EQ description
// ...
result = outCollection -> AddEffect ( kEffectID_MyFourBandEQ , aDesc4 );
}
if ( result == AAX_SUCCESS )
{
outCollection -> SetManufacturerName ( "My Plug -Ins , Inc." );
outCollection -> AddPackageName ( " MyEQ Plug -In" );
outCollection -> AddPackageName ( " MyQ" ); // Short name
outCollection -> SetPackageVersion ( 1 );
}
return result ;
}
Registering multiple Effects in a single Collection

Lowest level: Algorithm components

In order to register an algorithm component, a plug-in must describe the component's external interface. This includes each of the component's ports and any other fi elds in its context structure, a reference to its processing function entrypoint (its "Process Procedure", or ProcessProc,) and any other special properties that the host should know about.
The description of a context structure involves a set of port definitions, which can be "hard-wired" to receive data from the host (such as audio buffers), from the plug-in's data model (such as packets of coefficients), or even from past calls to the algorithm (private, persistent algorithm state). See Real-time algorithm callback for more information on an algorithm's context structure.
static void DescribeAlgorithmComponent( AAX_IComponentDescriptor * outDesc )
{
.
.
.
// Subscribe context fields to host-provided services or information
err = outDesc->AddField ( eAlgFieldID_AudioIn, kAAX_FieldTypeAudioIn ); AAX_ASSERT(err == 0);
err = outDesc->AddField ( eAlgFieldID_AudioOut, kAAX_FieldTypeAudioOut ); AAX_ASSERT (err == 0);
err = outDesc->AddField ( eAlgFieldID_BufferSize, kAAX_FieldTypeAudioBufferLength ); AAX_ASSERT (err == 0);
// Register context fields as communications destinations
err = outDesc->AddDataInPort ( eAlgPortID_BypassIn, sizeof (int32_t) ); AAX_ASSERT (err == 0);
err = outDesc->AddDataInPort ( eAlgPortID_CoefsGainIn, sizeof (SDemoGain_CoefsGain) ); AAX_ASSERT (err == 0);
.
.
.
}
virtual AAX_Result AddDataInPort(AAX_CFieldIndex inFieldIndex, uint32_t inPacketSize, AAX_EDataInPortType inPortType=AAX_eDataInPortType_Buffered)=0
Adds a custom data port to the algorithm context.
Populating a single AAX_IComponentDescriptor interface

Algorithm callback properties

A set of callback properties is required when adding a Process Procedure to an algorithm component. This is done via the AAX_IPropertyMap interface. Using distinct property maps, a single component may register multiple versions of its callback. For example, an audio processing component might register mono and stereo callbacks, or Native and TI callbacks, assigning each the applicable property mapping. This allows the host to determine the correct callback to use depending on the environment in which the plug-in is instantiated.
static void DescribeAlgorithmComponent( AAX_IComponentDescriptor * outDesc )
{
AAX_IPropertyMap * properties = outDesc->NewPropertyMap();
.
.
.
properties->Clear ();
properties->AddProperty ( AAX_eProperty_ManufacturerID, cDemoGain_ManufactureID );
properties->AddProperty ( AAX_eProperty_ProductID, cDemoGain_ProductID );
properties->AddProperty ( AAX_eProperty_CanBypass, true );
// Native and AudioSuite versions
properties->AddProperty ( AAX_eProperty_PlugInID_Native, cDemoGain_PlugInID_Native );
properties->AddProperty ( AAX_eProperty_PlugInID_AudioSuite, cDemoGain_PlugInID_AudioSuite ); // Since this is a linear plug-in the RTAS version can also be an AudioSuite version.
properties->AddProperty ( AAX_eProperty_DSP_AudioBufferLength, kAAX_NativeAudioBufferLength_Default);
err = outDesc->AddProcessProc_Native ( DemoGain_AlgorithmProcessFunction <1, 1, 1<<kAAX_NativeAudioBufferLength_Default>, properties ); AAX_ASSERT (err == 0);
// TI DSP Version
properties->AddProperty ( AAX_eProperty_PlugInID_TI, cDemoGain_PlugInID_TI );
}
@ AAX_eAudioBufferLengthDSP_Default
Definition: AAX_Enums.h:166
@ AAX_eStemFormat_Mono
M.
Definition: AAX_Enums.h:234
@ AAX_eProperty_DSP_AudioBufferLength
Audio buffer length for DSP processing callbacks. One of AAX_EAudioBufferLengthDSP.
Definition: AAX_Properties.h:348
@ AAX_eProperty_OutputStemFormat
Output stem format. One of AAX_EStemFormat.
Definition: AAX_Properties.h:341
@ AAX_eProperty_ProductID
Four-character osid-style Effect identifier.
Definition: AAX_Properties.h:111
@ AAX_eProperty_TI_SharedCycleCount
Shared cycle count (outer, per clump, loop overhead)
Definition: AAX_Properties.h:412
@ AAX_eProperty_TI_InstanceCycleCount
Instance cycle count (inner, per instance, loop overhead)
Definition: AAX_Properties.h:418
@ AAX_eProperty_CanBypass
The plug-in supports a Master Bypass control.
Definition: AAX_Properties.h:387
@ AAX_eProperty_PlugInID_TI
Four-character osid-style plug-in type identifier for real-time TI-accelerated audio Effect types.
Definition: AAX_Properties.h:168
@ AAX_eProperty_PlugInID_Native
Four-character osid-style plug-in type identifier for real-time native audio Effects.
Definition: AAX_Properties.h:130
@ AAX_eProperty_ManufacturerID
Four-character osid-style manufacturer identifier.
Definition: AAX_Properties.h:98
@ AAX_eProperty_PlugInID_AudioSuite
Four-character osid-style plug-in type identifier for offline native audio Effects.
Definition: AAX_Properties.h:148
@ AAX_eProperty_InputStemFormat
Input stem format. One of AAX_EStemFormat.
Definition: AAX_Properties.h:334
virtual AAX_IPropertyMap * NewPropertyMap() const =0
Creates a new, empty property map.
virtual AAX_Result AddProcessProc_Native(AAX_CProcessProc inProcessProc, AAX_IPropertyMap *inProperties=NULL, AAX_CInstanceInitProc inInstanceInitProc=NULL, AAX_CBackgroundProc inBackgroundProc=NULL, AAX_CSelector *outProcID=NULL)=0
Registers an algorithm processing entrypoint (process procedure) for the native architecture.
Generic plug-in description property map.
Definition: AAX_IPropertyMap.h:59
virtual AAX_Result AddProperty(AAX_EProperty inProperty, AAX_CPropertyValue inValue)=0
Add a property to a property map.
Adding properties to a component description
AAX does not require that every value in AAX_IPropertyMap be assigned by the developer. However, if a speci c value is not assigned to one of an element's properties then the element must support any value for that property. For example, if an audio processing component does not provide any stem format properties then the host will assume that the callback will support any stem format.

Checking Results

Summary

The Problem

With plain AAX_Result values it can be challenging to properly detect and handle error states. Each description method call returns an AAX_Result to indicate success or failure, and often problems in a plug-in's configuration can be addressed by properly detecting and resolving errors that occur here. However, adding a return value check after ever method and providing conditional logic in the case of a failure is onerous, ugly, and difficult to maintain.
result = descriptor->SomeMethod();
result = descriptor->AnotherMethod(); // oops! might ignore an error
// --------------------------------------------------
// Safer, but not a good solution:
// Information about the errors is lost, the
// merged error code is meaningless, and
// debugging to find the location of the
// failure is hard.
//
result |= descriptor->SomeMethod();
result |= descriptor->AnotherMethod();
// ...
if (AAX_SUCCESS != result)
{
// handle the merged error code
}
// --------------------------------------------------
// This is also not a good solution:
// There is no actual handling of errors
// (from the SDK example plug-ins)
//
result = descriptor->SomeMethod();
result = descriptor->AnotherMethod();
// --------------------------------------------------
// This is correct but is too hard
//
result = descriptor->SomeMethod();
if (AAX_SUCCESS != result) {
// logic to handle this error:
// assert and/or log the failure?
// return or continue execution?
}
result = descriptor->AnotherMethod();
if (AAX_SUCCESS != result) {
// ditto
}
AAX_Result based error checking is awkward

The Solution

The AAX_CheckedResult class is designed to solve this problem. AAX_CheckedResult can be used just like a plain-old-data AAX_Result :
result = descriptor->SomeMethod();
result = descriptor->AnotherMethod();
Definition: AAX_Exception.h:317
Simpler result checking with AAX_CheckedResult
When a failure is encountered, AAX_CheckedResult will:
To make this safe to use in the Describe routine, the AAX Library includes a try/catch block around the call to the plug-in's GetEffectDescriptions() routine.
Warning
Do not use AAX_CheckedResult anywhere where an exception could escape to the host (GetEffectDescriptions() is OK)

Handling Errors and Managing Control Flow

With the basic approach shown above, any error which is encountered will throw an exception which will cancel the plug-in's registration and prevent the plug-in from being shown in the host. However, most errors can be safely handled without canceling the entire plug-in registration.
// effect 1 registration
result = DescribeMyEffect1( effect1Descriptor );
result = outCollection->AddEffect( myEffect1ID, effect1Descriptor );
// effect 2 registration
result = DescribeMyEffect2( effect2Descriptor );
result = outCollection->AddEffect( myEffect2ID, effect2Descriptor );
Example with no error handling
In this example, a failure when describing either individual effect will prevent the other effect from being registered. Registration of individual ProcessProcs within a single effect, e.g. for different stem formats, is similar.
To allow the registration of other effects to proceed in the event of a failure, any exceptions thrown during the registration of one effect should be caught and should only prevent the registration of that individual effect.
// effect 1 registration
try {
result = DescribeMyEffect1( effect1Descriptor );
result = outCollection->AddEffect( myEffect1ID, effect1Descriptor );
}
catch (const AAX_CheckedResult::Exception& ex) {
// log the error using ex.What()
// swallow the exception and proceed
}
// effect 2 registration
try {
result = DescribeMyEffect2( effect2Descriptor );
result = outCollection->AddEffect( myEffect2ID, effect2Descriptor );
}
catch (const AAX_CheckedResult::Exception& ex) {
// ditto
}
Definition: AAX_Exception.h:147
Example of error handling with try/catch
This solves the problem fully, but it is still cumbersome - especially when registering a long list of separate ProcessProc variants!
The AAX_SWALLOW_MULT macro makes it easier to handle errors which are thrown by AAX_CheckedResult :
// effect 1 registration
result = DescribeMyEffect1( effect1Descriptor );
result = outCollection->AddEffect( myEffect1ID, effect1Descriptor );
);
// effect 2 registration
result = DescribeMyEffect2( effect2Descriptor );
result = outCollection->AddEffect( myEffect2ID, effect2Descriptor );
);
#define AAX_SWALLOW_MULT(...)
Executes X in a try/catch block that catches AAX_CheckedResult exceptions.
Definition: AAX_Exception.h:475
Example of error handling with AAX_SWALLOW_MULT
Variations
For examples of AAX_CheckedResult in use, see the DemoGain_Multichannel and DemoGain_UpMixer plug-ins

Describe Validation

Validation with DSH

You can validate your plug-in's Describe routine using the DigiShell command-line tool. The validation command is available directly in the aaxh dish and is also available through an AAX Validator test module:
aaxh dish
dsh> load_dish aaxh
dsh> loadpi "/quoted/path/without escape chars/MyPlugIn.aaxplugin"
dsh> getdescriptionvalidationinfo 0
AAX Validator
dsh> load_dish aaxval
dsh> runtest [test.describe_validation, "/quoted/path/without escape chars/MyPlugIn.aaxplugin"]

Validation with Pro Tools

Beginning in Pro Tools 12.8.2, developer builds of Pro Tools will also check plug-in describe routines and will present an alert dialog when the plug-in is scanned if any aspect of the plug-in's describe code has failed the validation step.
Describe validation warning in a Pro Tools developer build
Describe validation warning in a Pro Tools developer build
The specific kinds of errors which were encountered will be printed to the DigiTrace log file:
13033.502646,00307,0073: ERROR: Unknown target host for the plug-in.
13033.502662,00307,0073: ERROR: PlugInID property is missing for a ProcessProc (process, initialization, or background function).
13033.502734,00307,0e0f: CMN_TRACEASSERT  Sandbox.aaxplugin configuration contains 2 errors. See the DigiTrace log or run the AAX Validator for more info. (0 == numErrors)
This check may be suppressed using the following DigiOption:
TestPlugInDescriptions 0

Additional Topics

See also
Plug-in meters

Classes

class  AAX_ICollection
 Interface to represent a plug-in binary's static description. More...
 
class  AAX_IComponentDescriptor
 Description interface for an AAX plug-in component. More...
 
class  AAX_IEffectDescriptor
 Description interface for an effect's (plug-in type's) components. More...
 
class  AAX_IPropertyMap
 Generic plug-in description property map. More...
 

Functions

AAX_Result AAXRegisterPlugin (IACFUnknown *pUnkHost, IACFPluginDefinition **ppPluginDefinition)
 The main plug-in registration method. More...
 
AAX_Result GetEffectDescriptions (AAX_ICollection *inCollection)
 The plug-in's static Description entrypoint. More...
 

Function Documentation

◆ AAXRegisterPlugin()

AAX_Result AAXRegisterPlugin ( IACFUnknown pUnkHost,
IACFPluginDefinition **  ppPluginDefinition 
)

The main plug-in registration method.

This method determines the number of components defined in the dll. The implementation of this method in the AAX library calls the following function, which must be implemented somewhere in your plug-in:

Wrapped by ACFRegisterPlugin()

Referenced by ACFRegisterPlugin().

Here is the caller graph for this function:

◆ GetEffectDescriptions()

AAX_Result GetEffectDescriptions ( AAX_ICollection inCollection)

The plug-in's static Description entrypoint.

This function is responsible for describing an AAX plug-in to the host. It does this by populating an AAX_ICollection interface.

This function must be included in every plug-in that links to the AAX library. It is called when the host first loads the plug-in.

Parameters
[out]inCollection
Collaboration diagram for Description callback: