Note: A more recent version of this draft is available here
With Zen becoming more stable (especially with the 1.4 release), it is now time to start on opening it up to other developers. I am going to release 2 Zen API’s:
- the ZenAwareAudioFX API is a small extension to AudioEffectX, designed for cooperation between Zen and its hosted plugins.
- the ZenDB API will provide access to the local Zen database, and will allow developers to run searches to implement their own presets browser/manager.
Let me focus on the first API, which is the one I have mostly been working on lately. The need for this API stemmed from the need to deal with complex presets, with dependencies on data files (typically, samples) managed outside of the plugin. Absynth is a good example, and if you try to load a preset into Absynth without having the required .wav files in the proper folder, you will be greeted by an error message.
The ZenAwareAudioFX class aims to correct this, by enabling the plugin to communicate information about the required external files (that I call “assets”) it needs for the current preset. Everything is based on the existing mechanisms in the VST SDK, namely:
- The host (e.g, Zen) will send requests to the Zen-aware plugin using vendorSpecific calls
- The plugin will query the host using hostVendorSpecific calls
The ZenAwareAudioFX class takes care of all these calls, and leaves you with a few high level methods. These methods are pure virtual, so you simply have to inherit from ZenAwareAudioFX instead of AudioEffectX, and implement these methods in your plugin.
The methods you will need to implement are explained below:
virtual bool hasExternalAssets() const;This tells Zen if your plugin uses external assets. Usually this will return true, as you wouldn’t be here otherwise !
virtual unsigned int zenGetNumberOfAssets() const;This tells how many assets are used by the current preset.
virtual Zen::ZenErrorCode zenGetAssetName(unsigned int idx, char* assetName) const;This returns the name of the nth asset in the current preset. The host (Zen) will provide a char[128] buffer in assetName for you to write in. This name will be used to uniquely identify your asset among others for the same plugin, so if you use numeric ID’s for your assets, you can use itoa or equivalent to fill in the name.
virtual unsigned int zenGetAssetDataSize(unsigned int idx) const;As far as Zen is concerned, assets are opaque blocks of data with a name and a size. Zen will call this to know the required size, so that it can allocate it before calling the next method.
virtual Zen::ZenErrorCode zenGetAssetData(unsigned int idx, void* data) const;This sends the nth asset data to Zen. You just need to write into the provided data area (which has been allocated by Zen according to the size you declared in the previous method), using whatever serialization mechanism you want. Zen will associate this data block with the preset, upload it to the server, and distribute it to the clients.
typedef struct {
const char *assetName;
unsigned int assetSize;
void* data;
} ZenAssetData;
Zen::ZenErrorCode zenQueryAssetData(Zen::ZenAssetData* data);This is used by the plugin to retrieve the asset from Zen. You will actually have to call this twice: first fill in assetName and set data to NULL. The call will return assetSize. Then allocate your memory area according to assetSize, set the data pointer in the ZenAssetData structure, and call this method again – Zen will then fill the area with the asset data.