AUv2+macOS cannot create effect plugins
When using this command to create an AUv2 on a Mac mini (M1, 2020) with Clang, the plugin is recognized as an instrument plugin instead of an effect plugin in REAPER, FL Studio, and Logic Pro.
git clone https://github.com/baconpaul/clap-c99-distortion
cd clap-c99-distortion
git submodule update --init --recursive
cmake -Bignore/bld
cmake --build ignore/bld
cd ..
git clone https://github.com/free-audio/clap.git
git clone https://github.com/free-audio/clap-wrapper.git
git clone https://github.com/apple/AudioUnitSDK.git
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_SDK_ROOT="../clap" -DVST3_SDK_ROOT="../vst3sdk" -DCLAP_WRAPPER_BUILD_AUV2=ON -DAUDIOUNIT_SDK_ROOT="../AudioUnitSDK" -DCLAP_WRAPPER_OUTPUT_NAME="clap-c99-distortion"
cmake --build build --config Release
Also, for AUv2 plugins, the vendor name appears as "cleveraudio.org" — is it possible to change this?
Separately from this, an error occurs with VST3 plugins created using the clap-wrapper on the macOS version of FL Studio. Most FL Studio users will likely choose CLAP, but I’d still like to ensure that the VST3 version can be loaded properly, just in case someone wants to use VST3 in FL Studio for some reason. (This issue is not a high priority)
On the Mac mini (M1, 2020), it has been confirmed that the VST3 loads correctly in REAPER, Bitwig, and Cubase 14.
There's a variety of ways to configure the clap wrapper, but absent any configuration it will make guesses.
You can see the same c99 distortion is actually included in the clap wrapper with the full configuration specified in cmake here
https://github.com/free-audio/clap-wrapper/blob/main/tests/clap-first-example/CMakeLists.txt
That uses cmake to set the type as aufx
you an also add an extension to your clap and specify it in code. Here's an example of that. https://github.com/baconpaul/six-sines/blob/43d10b2dc86017e2c30a8e0c80e44fc5c79abc47/src/clap/six-sines-clap-entry-impl.cpp#L161
I think for your command line driven approach vs cmake style approach to work, you would want your clap to implement the auv2 wrapper extension so it can advertise the metadata facts you want, as shown above.
My guess is the VST3 fails to load in FL for the same reason the AU shows the wrong topology; it's configured weirdly as a synth with no midi ports and an audio in. Although I haven't tried the vst3 which emerges from the embedded example in FL, I have shipped other wrapper based plugins which work in FL.
Windows and VST3 worked perfectly with the first command in Ableton Live 12, Bitwig Studio 5, Cubase 13, FL Studio 2024, REAPER 7, and Studio One 6, so I didn't notice these options existed! Does this mean macOS is quite unusual in this regard?
When I compiled two simple CLAPs (plugin_a and plugin_b) on macOS using the zsh script below to generate VST3 and AUv2 formats, I noticed that the VST3s couldn't be loaded in FL Studio and Ableton Live, and the AUv2s only displayed plugin_a in each host. (Strangely, Ableton Live only displayed plugin_b. In any case, none of the DAWs could display both AUv2 plugins.)
I found a technique to easily load an AUv2 as an effect by directly editing plugin_a.component/Contents/Info.plist to change aumu to aufx, but with the current situation where only one plugin is displayed, I can't use this method either.
If the VST3 loading issue was only with FL Studio, it would be more manageable, but since Ableton Live can't load it either, it seems when using clap-wrapper on macOS, it's essential to learn how to use cmake or add new extensions to clap.
plugin.cpp
#include <cstring>
#include <cstdio>
#include <cmath>
#include "clap/include/clap/clap.h"
static const clap_plugin_descriptor_t plugin_descriptor = {
.clap_version = CLAP_VERSION_INIT,
#if defined(PLUGIN_A)
.id = "com.example.plugin_a",
.name = "plugin_a",
#endif
#if defined(PLUGIN_B)
.id = "com.example.plugin_b",
.name = "plugin_b",
#endif
.vendor = "example.com",
.url = "example.com",
.manual_url = "example.com",
.support_url = "example.com",
.version = "1.0.0",
.description = "",
.features = (const char *[]) {
CLAP_PLUGIN_FEATURE_AUDIO_EFFECT,
CLAP_PLUGIN_FEATURE_STEREO,
NULL,
},
};
class my_plug_t {
public:
clap_plugin_t plugin;
const clap_host_t *host;
};
static const clap_plugin_audio_ports_t audio_ports = {
.count = [] (const clap_plugin_t *plugin, bool is_input) -> uint32_t {
return 1;
},
.get = [] (const clap_plugin_t *plugin,uint32_t index,bool is_input,clap_audio_port_info_t *info) {
if (index > 0) return false;
info->id = 0;
snprintf(info->name, sizeof(info->name), "%s", "My Port Name");
info->channel_count = 2;
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->port_type = CLAP_PORT_STEREO;
info->in_place_pair = CLAP_INVALID_ID;
return true;
}
};
static const clap_plugin_t pluginClass = {
.desc = &plugin_descriptor,
.plugin_data = nullptr,
.init = [] (const clap_plugin *PLUGIN) -> bool {return true;},
.destroy = [] (const clap_plugin *PLUGIN) {
my_plug_t *plugin = static_cast<my_plug_t *>(PLUGIN->plugin_data);
free(plugin);
},
.activate = [] (const clap_plugin *PLUGIN, double SRATE, uint32_t minimumFramesCount, uint32_t maximumFramesCount) -> bool {return true;},
.deactivate = [] (const clap_plugin *PLUGIN) {},
.start_processing = [] (const clap_plugin *PLUGIN) -> bool {return true;},
.stop_processing = [] (const clap_plugin *PLUGIN) {},
.reset = [] (const clap_plugin *PLUGIN) {},
.process = [] (const clap_plugin *PLUGIN, const clap_process_t *process) -> clap_process_status {
my_plug_t *plugin = static_cast<my_plug_t *>(PLUGIN->plugin_data);
const uint32_t nframes = process->frames_count;
for (uint32_t i = 0;i < nframes;i++) {
#if defined(PLUGIN_A)
process->audio_outputs[0].data32[0][i] = sin(process->audio_inputs[0].data32[0][i]);
process->audio_outputs[0].data32[1][i] = sin(process->audio_inputs[0].data32[1][i]);
#endif
#if defined(PLUGIN_B)
process->audio_outputs[0].data32[0][i] = abs(process->audio_inputs[0].data32[0][i]);
process->audio_outputs[0].data32[1][i] = abs(process->audio_inputs[0].data32[1][i]);
#endif
}
return CLAP_PROCESS_CONTINUE;
},
.get_extension = [] (const clap_plugin *plugin, const char *id) -> const void * {
if (!strcmp(id, CLAP_EXT_AUDIO_PORTS)) return &audio_ports;
return nullptr;
},
.on_main_thread = [] (const clap_plugin *PLUGIN) {},
};
static const clap_plugin_factory_t pluginFactory = {
.get_plugin_count = [] (const clap_plugin_factory *factory) -> uint32_t {
return 1;
},
.get_plugin_descriptor = [] (const clap_plugin_factory *factory, uint32_t index) -> const clap_plugin_descriptor_t * {
return index == 0 ? &plugin_descriptor : nullptr;
},
.create_plugin = [] (const clap_plugin_factory *factory, const clap_host_t *host, const char *pluginID) -> const clap_plugin_t * {
if (!clap_version_is_compatible(host->clap_version) || strcmp(pluginID, plugin_descriptor.id)) return nullptr;
my_plug_t *plugin = (my_plug_t *) calloc(1, sizeof(my_plug_t));
plugin->host = host;
plugin->plugin = pluginClass;
plugin->plugin.plugin_data = plugin;
return &plugin->plugin;
},
};
extern "C" const clap_plugin_entry_t clap_entry = {
.clap_version = CLAP_VERSION_INIT,
.init = [] (const char *path) -> bool {
return true;
},
.deinit = [] () {},
.get_factory = [] (const char *factoryID) -> const void * {
return strcmp(factoryID, CLAP_PLUGIN_FACTORY_ID) ? nullptr : &pluginFactory;
},
};
zsh
git clone https://github.com/free-audio/clap.git
mkdir -p "plugin_a.clap/Contents/MacOS"
mkdir -p "plugin_b.clap/Contents/MacOS"
clang++ -std=c++20 -dynamiclib -o "plugin_a.clap/Contents/MacOS/plugin_a" "plugin.cpp" -DPLUGIN_A
clang++ -std=c++20 -dynamiclib -o "plugin_b.clap/Contents/MacOS/plugin_b" "plugin.cpp" -DPLUGIN_B
touch "plugin_a.clap/Contents/Info.plist"
touch "plugin_b.clap/Contents/Info.plist"
rm -rf clap
git clone https://github.com/free-audio/clap.git
git clone https://github.com/free-audio/clap-wrapper.git
git clone https://github.com/apple/AudioUnitSDK.git
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_SDK_ROOT="../clap" -DVST3_SDK_ROOT="../vst3sdk" -DCLAP_WRAPPER_BUILD_AUV2=ON -DAUDIOUNIT_SDK_ROOT="../AudioUnitSDK" -DCLAP_WRAPPER_OUTPUT_NAME="plugin_a"
cmake --build build --config Release
cp -r "build/plugin_a.vst3" "../"
cp -r "build/plugin_a.component" "../"
cd ..
rm -rf clap
rm -rf clap-wrapper
rm -rf AudioUnitSDK
git clone https://github.com/free-audio/clap.git
git clone https://github.com/free-audio/clap-wrapper.git
git clone https://github.com/apple/AudioUnitSDK.git
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_SDK_ROOT="../clap" -DVST3_SDK_ROOT="../vst3sdk" -DCLAP_WRAPPER_BUILD_AUV2=ON -DAUDIOUNIT_SDK_ROOT="../AudioUnitSDK" -DCLAP_WRAPPER_OUTPUT_NAME="plugin_b"
cmake --build build --config Release
cp -r "build/plugin_b.vst3" "../"
cp -r "build/plugin_b.component" "../"
cd ..
rm -rf clap
rm -rf clap-wrapper
rm -rf AudioUnitSDK
I added an extension to CLAP but it seems I still can't load the VST3 and AUv2. Is there something wrong with this code? Or is it really necessary to both use cmake and add extensions to CLAP? As far as I know, with this method, x.component/Contents/Info.plist will always default to aumu, and I feel I need to manually change it to aufx after generation. Is there by chance some process that automatically rewrites the Info.plist from CLAP information when loading AUv2?
(Since my method doesn't compile directly, I'm changing "clap/private/macros.h" to "../../../clap/include/clap/private/macros.h" in vst3.h and auv2.h to make it compile.)
plugin2.cpp
#include <cstring>
#include <cstdio>
#include <cmath>
#include "clap/include/clap/clap.h"
#include "clap-wrapper/include/clapwrapper/vst3.h"
#include "clap-wrapper/include/clapwrapper/auv2.h"
static const clap_plugin_descriptor_t plugin_descriptor = {
.clap_version = CLAP_VERSION_INIT,
#if defined(PLUGIN_A)
.id = "com.example.plugin2_a",
.name = "plugin2_a",
#endif
#if defined(PLUGIN_B)
.id = "com.example.plugin2_b",
.name = "plugin2_b",
#endif
.vendor = "example.com",
.url = "example.com",
.manual_url = "example.com",
.support_url = "example.com",
.version = "1.0.0",
.description = "",
.features = (const char *[]) {
CLAP_PLUGIN_FEATURE_AUDIO_EFFECT,
CLAP_PLUGIN_FEATURE_STEREO,
NULL,
},
};
// Clap Wrapper AUV2 Factory API
static bool clap_get_auv2_info(
const clap_plugin_factory_as_auv2 *factory,
uint32_t index,
clap_plugin_info_as_auv2_t *info
) {
if (index == 0) {
strncpy(info->au_type, "aufx", 5); // use the features to determine the type
strncpy(info->au_subt, "dist", 5);
return true;
} else {
return false;
}
}
// Clap Wrapper VST3 Factory API
static const clap_plugin_info_as_vst3 *clap_get_vst3_info(
const clap_plugin_factory_as_vst3 *f,
uint32_t index
) {
return nullptr;
}
class my_plug_t {
public:
clap_plugin_t plugin;
const clap_host_t *host;
};
static const clap_plugin_audio_ports_t audio_ports = {
.count = [] (const clap_plugin_t *plugin, bool is_input) -> uint32_t {
return 1;
},
.get = [] (const clap_plugin_t *plugin,uint32_t index,bool is_input,clap_audio_port_info_t *info) {
if (index > 0) return false;
info->id = 0;
snprintf(info->name, sizeof(info->name), "%s", "My Port Name");
info->channel_count = 2;
info->flags = CLAP_AUDIO_PORT_IS_MAIN;
info->port_type = CLAP_PORT_STEREO;
info->in_place_pair = CLAP_INVALID_ID;
return true;
}
};
static const clap_plugin_t pluginClass = {
.desc = &plugin_descriptor,
.plugin_data = nullptr,
.init = [] (const clap_plugin *PLUGIN) -> bool {return true;},
.destroy = [] (const clap_plugin *PLUGIN) {
my_plug_t *plugin = static_cast<my_plug_t *>(PLUGIN->plugin_data);
free(plugin);
},
.activate = [] (const clap_plugin *PLUGIN, double SRATE, uint32_t minimumFramesCount, uint32_t maximumFramesCount) -> bool {return true;},
.deactivate = [] (const clap_plugin *PLUGIN) {},
.start_processing = [] (const clap_plugin *PLUGIN) -> bool {return true;},
.stop_processing = [] (const clap_plugin *PLUGIN) {},
.reset = [] (const clap_plugin *PLUGIN) {},
.process = [] (const clap_plugin *PLUGIN, const clap_process_t *process) -> clap_process_status {
my_plug_t *plugin = static_cast<my_plug_t *>(PLUGIN->plugin_data);
const uint32_t nframes = process->frames_count;
for (uint32_t i = 0;i < nframes;i++) {
#if defined(PLUGIN_A)
process->audio_outputs[0].data32[0][i] = sin(process->audio_inputs[0].data32[0][i]);
process->audio_outputs[0].data32[1][i] = sin(process->audio_inputs[0].data32[1][i]);
#endif
#if defined(PLUGIN_B)
process->audio_outputs[0].data32[0][i] = abs(process->audio_inputs[0].data32[0][i]);
process->audio_outputs[0].data32[1][i] = abs(process->audio_inputs[0].data32[1][i]);
#endif
}
return CLAP_PROCESS_CONTINUE;
},
.get_extension = [] (const clap_plugin *plugin, const char *id) -> const void * {
if (!strcmp(id, CLAP_EXT_AUDIO_PORTS)) return &audio_ports;
return nullptr;
},
.on_main_thread = [] (const clap_plugin *PLUGIN) {},
};
static const clap_plugin_factory_t pluginFactory = {
.get_plugin_count = [] (const clap_plugin_factory *factory) -> uint32_t {
return 1;
},
.get_plugin_descriptor = [] (const clap_plugin_factory *factory, uint32_t index) -> const clap_plugin_descriptor_t * {
return index == 0 ? &plugin_descriptor : nullptr;
},
.create_plugin = [] (const clap_plugin_factory *factory, const clap_host_t *host, const char *pluginID) -> const clap_plugin_t * {
if (!clap_version_is_compatible(host->clap_version) || strcmp(pluginID, plugin_descriptor.id)) return nullptr;
my_plug_t *plugin = (my_plug_t *) calloc(1, sizeof(my_plug_t));
plugin->host = host;
plugin->plugin = pluginClass;
plugin->plugin.plugin_data = plugin;
return &plugin->plugin;
},
};
extern "C" const clap_plugin_entry_t clap_entry = {
.clap_version = CLAP_VERSION_INIT,
.init = [] (const char *path) -> bool {
return true;
},
.deinit = [] () {},
.get_factory = [] (const char *factory_id) -> const void * {
if (strcmp(factory_id, CLAP_PLUGIN_FACTORY_ID) == 0) return &pluginFactory;
if (strcmp(factory_id, CLAP_PLUGIN_FACTORY_INFO_AUV2) == 0) {
static const struct clap_plugin_factory_as_auv2 auv2_factory =
{
"ExCo",// manu
"ExampleCom",// manu name
clap_get_auv2_info
};
return &auv2_factory;
}
if (strcmp(factory_id, CLAP_PLUGIN_FACTORY_INFO_VST3) == 0)
{
static const struct clap_plugin_factory_as_vst3 vst3_factory =
{
"ExampleCom",
"https://example.com",
"",
clap_get_vst3_info
};
return &vst3_factory;
}
return nullptr;
},
};
zsh
mkdir -p "plugin2_a.clap/Contents/MacOS"
mkdir -p "plugin2_b.clap/Contents/MacOS"
clang++ -std=c++20 -dynamiclib -o "plugin2_a.clap/Contents/MacOS/plugin2_a" "plugin2.cpp" -DPLUGIN_A
clang++ -std=c++20 -dynamiclib -o "plugin2_b.clap/Contents/MacOS/plugin2_b" "plugin2.cpp" -DPLUGIN_B
touch "plugin2_a.clap/Contents/Info.plist"
touch "plugin2_b.clap/Contents/Info.plist"
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_SDK_ROOT="../clap" -DVST3_SDK_ROOT="../vst3sdk" -DCLAP_WRAPPER_BUILD_AUV2=ON -DAUDIOUNIT_SDK_ROOT="../AudioUnitSDK" -DCLAP_WRAPPER_OUTPUT_NAME="plugin2_a"
cmake --build build --config Release
cp -r "build/plugin2_a.vst3" "../"
cp -r "build/plugin2_a.component" "../"
cd ..
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_SDK_ROOT="../clap" -DVST3_SDK_ROOT="../vst3sdk" -DCLAP_WRAPPER_BUILD_AUV2=ON -DAUDIOUNIT_SDK_ROOT="../AudioUnitSDK" -DCLAP_WRAPPER_OUTPUT_NAME="plugin2_b"
cmake --build build --config Release
cp -r "build/plugin2_b.vst3" "../"
cp -r "build/plugin2_b.component" "../"
cd ..
Have you installed your clap already, this way it can be scanned and the correct AUv2 bundle setting can be determined.
Is this about loading the AUv2 rather than building it? Even if I pre-install the CLAP plugin into /Library/Audio/Plug-Ins/CLAP and then build the AUv2 afterwards, it seems that with my current method, it still cannot be loaded properly.
As for AUv2, for now, I've managed to get both AUv2 plugins to show up in the host and appear to be functioning correctly by manually changing the type in the Info.plist to aufx, and randomly changing the manufacturer and subtype for each plugin.
Regarding VST3, it still doesn't show up at all in some hosts, so I plan to keep experimenting with that a bit more.
Let me take a look..
I found that FL Studio can be made to work by manually changing the Type to Effect from this page and clicking Apply changes. However, with this method, the Vendor remains blank.
↓
Looks like the top level approach is broken and needs some love. :(
There's a variety of ways to configure the clap wrapper, but absent any configuration it will make guesses.
You can see the same c99 distortion is actually included in the clap wrapper with the full configuration specified in cmake here
https://github.com/free-audio/clap-wrapper/blob/main/tests/clap-first-example/CMakeLists.txt
That uses cmake to set the type as
aufx
I wanted to try this method, and since I don't know how to use cmake at all, I might be wrong, but I came up with this:
git clone https://github.com/free-audio/clap-wrapper.git
cd clap-wrapper
mkdir build
cmake -B build -DCMAKE_CXX_STANDARD=20 -DCLAP_WRAPPER_BUILD_TESTS=ON -DCLAP_WRAPPER_BUILD_AUV2=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release
When using this method on macOS, I couldn't load the VST3 in FL Studio or Ableton Live. Is this zsh script incorrect?
However, on Windows, using this script allows it to load normally. (Well, on Windows it was working perfectly from the beginning using the method described in "Getting Started".)
Also, why is the parameter order in AUv2 different from the others?
Could it be that they're arranged in order of lower
ParamIds?
https://github.com/free-audio/clap-wrapper/blob/5ba58f16a7816085d46cb8b7bb40b1eb1d9561d2/tests/clap-first-example/distortion_clap.cpp#L40-L45
By making both the CLAP and VST3 builds universal binaries, I was able to load the VST3 version in FL Studio and Ableton Live! The issue was that some hosts couldn’t load the plugin properly when it was built for Apple Silicon only...
In other words, by doing this, I was able to make all plugin formats loadable in all hosts:
git clone https://github.com/free-audio/clap-wrapper.git
cd clap-wrapper
mkdir build
cmake -B build \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_BUILD_TYPE=Release \
-DCLAP_WRAPPER_BUILD_TESTS=ON \
-DCLAP_WRAPPER_BUILD_AUV2=ON
cmake --build build --config Release
you an also add an extension to your clap and specify it in code. Here's an example of that. https://github.com/baconpaul/six-sines/blob/43d10b2dc86017e2c30a8e0c80e44fc5c79abc47/src/clap/six-sines-clap-entry-impl.cpp#L161
Next, I tried this method. I was able to successfully modify vendor and other info for the VST3 version using this, but I’m still struggling to get it to work with AUv2.
To generate AUv2 using only command line without creating my own CMakeLists.txt, one of these two approaches is probably used, right?
- During the AUv2 build, it reads something matching
-DCLAP_WRAPPER_OUTPUT_NAMEfrom the CLAP folder and retrieves the necessary info from theCLAP_PLUGIN_FACTORY_INFO_AUV2extension. - If it can't retrieve the info during the AUv2 build, it sets placeholder defaults and later, when the AUv2 is loaded by the DAW, it fetches the actual values from the
CLAP CLAP_PLUGIN_FACTORY_INFO_AUV2extension and maybe rewrites the plist or something similar.
I also looked into whether there might be an option like -DCLAP_WRAPPER_AUV2_INSTRUMENT_TYPE="aufx", but couldn’t find one. However, after experimenting, I found that changing this part made it work, and so far the AUv2 version seems to be working fine, so I plan to go with this method for now:
https://github.com/free-audio/clap-wrapper/blob/5ba58f16a7816085d46cb8b7bb40b1eb1d9561d2/cmake/top_level_default.cmake#L33-L36
INSTRUMENT_TYPE "${CLAP_WRAPPER_AUV2_INSTRUMENT_TYPE}"
MANUFACTURER_NAME "${CLAP_WRAPPER_AUV2_MANUFACTURER_NAME}"
MANUFACTURER_CODE "${CLAP_WRAPPER_AUV2_MANUFACTURER_CODE}"
SUBTYPE_CODE "${CLAP_WRAPPER_AUV2_SUBTYPE_CODE}"
CMake command:
mkdir build
cmake -B build \
-DCMAKE_CXX_STANDARD=20 \
-DCMAKE_OSX_ARCHITECTURES="arm64;x86_64" \
-DCMAKE_BUILD_TYPE=Release \
-DCLAP_WRAPPER_OUTPUT_NAME="The Name of your CLAP" \
-DCLAP_WRAPPER_BUILD_AUV2=ON \
-DCLAP_WRAPPER_AUV2_MANUFACTURER_NAME="cleveraudio.org" \
-DCLAP_WRAPPER_AUV2_MANUFACTURER_CODE="clAd" \
-DCLAP_WRAPPER_AUV2_SUBTYPE_CODE="gWrp" \
-DCLAP_WRAPPER_AUV2_INSTRUMENT_TYPE="aumu"
I'll investigate tomorrow the phenomenon where the AUv2 parameters seem to be arranged in order of ascending ParamIds...
Honestly I’ve never built an auv2 with just command line. I write my own Cmake to do my full build
I’m sure what you want to do could be done but I don’t know if the cmake from the command line only constraint can do it - that would probably require basically writing the cmake you would write and making everything a variable
When I check clap-wrapper/build/plugin3_as_auv2-build-helper, it looks like it's properly replaced, so I think I'll go ahead and use my own modified version for personal use!
Currently, the parameters in AUv2 are indeed ordered by ascending ParamIds, and after trying various things, it seems that changing them like this will allow us to match the parameter order with CLAP. Basic tests such as whether automation and state are preserved even when changing the parameter indices in CLAP have passed, but there might still be some bugs.
For WrapAsAUV2::GetParameterList, I basically referred to this: https://github.com/apple/AudioUnitSDK/blob/e789bc83ddc07cbf80e7bfaf84f1ade975287400/src/AudioUnitSDK/AUBase.cpp#L1925-L1948
--- a/src/detail/auv2/auv2_base_classes.h
+++ b/src/detail/auv2/auv2_base_classes.h
@@ -554,6 +554,7 @@ class WrapAsAUV2 : public ausdk::AUBase,
#endif
std::map<uint32_t, std::unique_ptr<Clap::AUv2::Parameter>> _parametertree;
Clumps _clumps;
+ std::vector<clap_id> _ordered_parameter_ids;
CFStringRef _current_program_name = 0;
--- a/src/wrapasauv2.cpp
+++ b/src/wrapasauv2.cpp
@@ -326,6 +326,7 @@ void WrapAsAUV2::setupParameters(const clap_plugin_t* plugin, const clap_plugin_
// creating parameters.
_clumps.reset();
+ _ordered_parameter_ids.clear();
auto* p = _plugin->_ext._params;
if (p)
{
@@ -335,6 +336,7 @@ void WrapAsAUV2::setupParameters(const clap_plugin_t* plugin, const clap_plugin_
{
if (p->get_info(_plugin->_plugin, i, ¶minfo))
{
+ _ordered_parameter_ids.push_back(paraminfo.id);
double result;
if (p->get_value(_plugin->_plugin, paraminfo.id, &result))
{
@@ -360,6 +362,21 @@ void WrapAsAUV2::setupParameters(const clap_plugin_t* plugin, const clap_plugin_
OSStatus WrapAsAUV2::GetParameterList(AudioUnitScope inScope, AudioUnitParameterID* outParameterList,
UInt32& outNumParameters)
{
+ if (inScope == kAudioUnitScope_Global)
+ {
+ UInt32 maxNumParams = _ordered_parameter_ids.size();
+
+ if (outParameterList != nullptr)
+ {
+ for (int i = 0; i < maxNumParams; ++i)
+ {
+ outParameterList[i] = _ordered_parameter_ids[i];
+ }
+ }
+
+ outNumParameters = maxNumParams;
+ return noErr;
+ }
return AUBase::GetParameterList(inScope, outParameterList, outNumParameters);
}
This code looks right but we also need to make sure it is properly invalidated in the rescan case.
@defiantnerd you and I should probably find an hour or two to make sure we write down and divide and conquer all the au stuff we’ve found last week or two.
Actually, there are different topics in this issue and I would suggest that you make different issues out of it @lewloiwc. Also check if it is still the case with 0.13.