aax_wrapper.h
The AAX format wrapper (AAX Native), for Pro Tools.
#include <sonore/aax_wrapper.h>- 6types
- 31other declarations
- Guides: Getting started, Platforms and formats
On this page
Design notes
Written against Avid's AAX SDK, which this repository does NOT carry. The SDK is Avid's, under their AAX SDK licence or the GPLv3; every developer who builds AAX downloads it under that licence themselves and points SONORE_AAX_SDK_ROOT at it. What is here is our code, under Apache-2.0, and it is only ever compiled against a copy of the SDK the builder obtained. Shipping the result is the same deal it is for every other framework: the AAX agreement with Avid, and a PACE signature on every binary. A developer build of Pro Tools loads unsigned plugins, which is how this file is tested.
Include it AFTER clap_wrapper.h, as formats.h does: the CLAP wrapper owns the machinery every format shares (the DSP instance, parameters, state, both editors), and this file adapts it to AAX's shape, so a .aaxplugin cannot behave differently from the .clap and .vst3 built from the same source.
AAX splits a plugin in two, and the split drives everything below:
- The DATA MODEL (AAX_CEffectParameters): parameters, state, latency, on the host's main thread. Ours holds the shared Instance.
- The ALGORITHM: a plain C callback over a "context" struct whose fields the description subscribes to host services -- audio, the buffer length, MIDI nodes. It is normally kept apart from the data model so it can run on a DSP card. AAX Native runs it in the same process, and the description says it MUST stay with the data model (Constraint_Location), so one private-data field carries a pointer to the data model and the callback renders through the shared Instance exactly as every other format's process call does.
What this does not do: AAX DSP (HDX) and AudioSuite, which need a different algorithm build and an offline processing model; host-drawn page tables for control surfaces; and main buses wider than stereo, where Pro Tools' channel order differs from the conventional one and a wrong order is silent.
Types 6
class Taper : public AAX_ITaperDelegate<float>
The plugin's own curve between AAX's normalised value and the plain one. Through plugin.h's functions, not a copy: the host's automation lane and the plugin's own knob have to agree about where a value sits, and that is only certain when one function answers both.
class Display : public AAX_IDisplayDelegate<float>
The text a host shows and parses: the same functions every format's readout uses, so "-6.0 dB" reads the same in Pro Tools as in the plugin.
What the private-data field holds: the data model the callback renders through. Written by Effect::ResetFieldData when the host sets up the instance's context.
The context the algorithm is called with. Each field is one host service the description subscribes, by its index (AAX_FIELD_INDEX). A field this plugin has no use for -- a MIDI node an effect never reads, a sidechain it does not take -- is still described, as a few bytes of private data nothing reads, because the host fills fields by index and an index left undescribed is a field it never fills.
class Effect : public AAX_CEffectParameters
One instance: the shared Instance every format drives, inside AAX's data model. Pro Tools creates it through create(), calls the parameter and chunk methods on its main thread, and the algorithm callback renders through it on the audio thread (render()).
class Gui : public AAX_CEffectGUI
The plugin's window inside Pro Tools'. The same choice of editor the other formats make -- native, or the page in the OS webview -- embedded in the view container the host gives (an HWND on Windows, an NSView on macOS).
Functions 19
- fn
constexpr AAX_CTypeID fourCC(const char* s)'abcd' from "abcd": the order AAX compares and stores type IDs in.aax::fourCC · aax_wrapper.h:93 - fn
inline AAX_CTypeID derivedCode(const char* id, const char* salt)A code DERIVED from the plugin's reverse-URI id and a salt: stable across builds and distinct per product and per layout, without anyone choosing a code and pasting it into the source -- which a generator would get wrong once and then ship forever. Letters and digits only, an upper-case letter first, because these appear in session files and in Avid's tools.aax::derivedCode · aax_wrapper.h:103 - fn
inline AAX_CTypeID manufacturerId()aax::manufacturerId · aax_wrapper.h:118 - fn
inline AAX_CTypeID productId()The product code: the one CMake was given, or one derived from the id.aax::productId · aax_wrapper.h:124 - fn
inline AAX_CTypeID typeIdFor(uint32_t channels)Each layout a plugin offers is a separate plugin TYPE to Pro Tools, with an id of its own, and a session names the type it used: these are forever.aax::typeIdFor · aax_wrapper.h:133 - fn
inline AAX_EStemFormat stemFor(uint32_t channels)aax::stemFor · aax_wrapper.h:137 - fn
inline bool offersWidth(uint32_t channels)The layouts this plugin offers Pro Tools: mono and stereo, where the descriptor's range allows them. Wider buses are not offered (see the banner).aax::offersWidth · aax_wrapper.h:144 - fn
inline const char* paramId(int index)The ids AAX knows parameters by: the table's index, as VST3's are, because the index IS a parameter's identity in every format and every saved session. "p0", "p1", ... -- well inside AAX's 31 characters.aax::paramId · aax_wrapper.h:151 - fn
inline int paramIndexOf(AAX_CParamID id)"p12" back to 12; -1 for anything else, the master bypass included.aax::paramIndexOf · aax_wrapper.h:162 - fn
inline bool isBypassId(AAX_CParamID id)aax::isBypassId · aax_wrapper.h:172 - fn
inline bool hasBypass()Effects get Pro Tools' master bypass; instruments do not, as in every other format: there is no dry signal to pass, and a host treats an instrument's bypass as its own mute.aax::hasBypass · aax_wrapper.h:179 - fn
inline uint32_t categoryOf()Where Pro Tools files the plugin in its menus, from the descriptor's category word. An instrument is a software generator whatever it says.aax::categoryOf · aax_wrapper.h:183 - fn
inline uint32_t packedVersion()"1.2.3" packed as AU packs it: major << 16 | minor << 8 | patch.aax::packedVersion · aax_wrapper.h:208 - fn
inline bool takesSidechain()A sidechain is offered to an effect whose DSP takes one: Pro Tools' key input, mono.aax::takesSidechain · aax_wrapper.h:314 - fn
inline uint32_t auxStemCount()Pro Tools gives aux outputs as mono or stereo stems only, so a wider aux bus is not offered, and the buses after it are not either: they are addressed by position in one array, and skipping one would move the rest.aax::auxStemCount · aax_wrapper.h:321 - fn
inline void AAX_CALLBACK renderAudio(RenderContext* const begin[], const void* end)The algorithm entry point: every instance Pro Tools is running in this call, each through its own data model.aax::renderAudio · aax_wrapper.h:875 - fn
template <typename Add> inline void addNames(const char* name, Add&& add)Names at the lengths Pro Tools picks between for narrow places: the full name, then 31, 16, 8 and 4 characters.aax::addNames · aax_wrapper.h:1180 - fn
inline AAX_Result describeType(AAX_IEffectDescriptor* effect, uint32_t channels)One plugin TYPE: the algorithm at one channel width.aax::describeType · aax_wrapper.h:1196 - fn
inline AAX_Result describe(AAX_ICollection* collection)aax::describe · aax_wrapper.h:1254
Constants 10
- const
constexpr AAX_CFieldIndex kFieldInputs = AAX_FIELD_INDEX(RenderContext, inputs)aax::kFieldInputs · aax_wrapper.h:303 - const
constexpr AAX_CFieldIndex kFieldOutputs = AAX_FIELD_INDEX(RenderContext, outputs)aax::kFieldOutputs · aax_wrapper.h:304 - const
constexpr AAX_CFieldIndex kFieldNumSamples = AAX_FIELD_INDEX(RenderContext, numSamples)aax::kFieldNumSamples · aax_wrapper.h:305 - const
constexpr AAX_CFieldIndex kFieldClock = AAX_FIELD_INDEX(RenderContext, clock)aax::kFieldClock · aax_wrapper.h:306 - const
constexpr AAX_CFieldIndex kFieldMidiIn = AAX_FIELD_INDEX(RenderContext, midiIn)aax::kFieldMidiIn · aax_wrapper.h:307 - const
constexpr AAX_CFieldIndex kFieldMidiOut = AAX_FIELD_INDEX(RenderContext, midiOut)aax::kFieldMidiOut · aax_wrapper.h:308 - const
constexpr AAX_CFieldIndex kFieldSideChain = AAX_FIELD_INDEX(RenderContext, sideChain)aax::kFieldSideChain · aax_wrapper.h:309 - const
constexpr AAX_CFieldIndex kFieldData = AAX_FIELD_INDEX(RenderContext, data)aax::kFieldData · aax_wrapper.h:310 - const
constexpr uint32_t kMaxFrames = 1024The most frames one call brings. AAX Native's largest buffer is 1024 (AAX_eAudioBufferLengthNative_Max); a longer call, which the host does not make, is rendered in slices of this rather than refused.aax::kMaxFrames · aax_wrapper.h:330 - const
constexpr AAX_CTypeID kChunkId = fourCC("SNRS")The chunk id for the SNRS state blob: the same versioned blob every format saves, so a session moved between hosts carries the same sound.aax::kChunkId · aax_wrapper.h:336
Macros 2
- macro
#define SONORE_AAX_MANUFACTURER "Sonr"The four-character codes Pro Tools files the plugin under, from sonore_add_aax(). The manufacturer is the developer's; the product is this plugin's. Both are written into every session that uses it, so they are chosen once and never changed.aax_wrapper.h:79 - macro
#define SONORE_AAX_PRODUCT ""aax_wrapper.h:82