FR: Allow custom VST3 UIDs

Hello,

I’m currently working on a project that uses a JUCE wrapper to replace a VST SDK-based plugin (and several other wrappers). With a matching Manufacturer Code and Plugin Code, I can get the VST2 and AU versions of the JUCE plugin to replace the existing plugin in DAW projects.

But for VST3, the UID that the host uses to identify plugins is partially hard-coded in JUCE:

inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0x9182FAEB, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) };

To get the new VST3 to replace the old one, the whole UID must be the same, so there is no choice but to modify this line in the JUCE source code.

My request then is some way of setting the entire VST3 UID with a JUCE setting.

Thank you for your consideration.

+1

I am dealing with the same issue, porting old code to JUCE and some way of assigning manual VST3 IDs. Any ideas?

This seems to do the trick (in my particular situation), but I’d appreciate some input from someone more experienced. So far only tested in Reaper (win and macOS).

In juce_VST3ModuleInfo.h:

[[maybe_unused]] static VST3Interface::Id getVST3InterfaceId (VST3Interface::Type interfaceType)
{
   #if JUCE_VST3_CAN_REPLACE_VST2
    if (interfaceType == VST3Interface::Type::controller || interfaceType == VST3Interface::Type::component)
        return VST3Interface::vst2PluginId (JucePlugin_VSTUniqueID, JucePlugin_Name, interfaceType);
   #endif

#if defined(CUSTOM_UID)
	if (interfaceType == VST3Interface::Type::component)
	{
		auto res = VST3Interface::Id();
		constexpr std::array<unsigned, 4> UID = CUSTOM_UID;

		for (int i = 0; i < 16; ++i)
		{
			const unsigned pos = i / 4;
			const unsigned off = (3 - (i % 4)) * 8; // big-endian
			res[i] = static_cast<std::byte>((UID[pos] >> off) & 0xFF);
		}
#if JUCE_WINDOWS
		std::swap(res[0], res[3]);
		std::swap(res[1], res[2]);
		std::swap(res[4], res[5]);
		std::swap(res[6], res[7]);
#endif

		return res;
	}
#endif

    return VST3Interface::jucePluginId (JucePlugin_ManufacturerCode, JucePlugin_PluginCode, interfaceType);
}

In your project’s preprocessor definitions (example):
CUSTOM_UID={0x01234567,0x89ABCDEF,0x78965412,0x19732846}

Rather than having to change JUCE can you use JUCE_VST3_COMPATIBLE_CLASSES to add the VST3 UID you need to be compatible with?

I must be doing something wrong, because this doesn’t work for me. I replaced the custom UID macro with this:
JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::hexStringToId(“0123456789ABCDEF7896541219732846”)
but Reaper doesn’t recognize it as the same plugin. It might also be a DAW issue, but that’s all the more reason to actually use the old UID.

Another (definitely not me doing things wrong) issue is that this approach doesn’t work if the user decides to go to a previous (pre-JUCE) version. Even though it would be a PITA to modify JUCE on every machine with every JUCE update, I’d still prefer to do that than introduce easily avoidable incompatibility.

EDIT: I guess the hexStringToId() approach needs some/all of the byte shuffling done when creating the UID string, is that correct? Still, I think my second point stands.

Yes you would need to check what the actual value is of the VST3 you want to replace.

Looking back at the implementation you’ve suggested I think if we add something like this we would expect the CUSTOM_UID to be the correct UID, no need to shuffle bytes. That should also make managing the change in JUCE for yourself that little bit easier.

Having it be the final UID without shuffling bytes is fair enough I guess.

I keep trying to figure out the hexStringToId() approach, but it just doesn’t want to work. I got to a point where my original implementation and hexStringToId() return the same byte array, but Reaper still doesn’t replace the instance with the new version.

I’m surprised, I thought reaper supported it.

Maybe check out the VST3PluginTestHost in the SDK (VST 3 Plug-in Test Host - VST 3 Developer Portal)

If nothing else I think you can use this to give you the UID you need from the original plugin.

I’m not sure how to check whether or not it works in the test host. I did just try it in Cubase and it doesn’t work there either, so I’m really confused…

EDIT: I just double checked and the byte arrays produced by my code and hexStringToId() are definitely the same, so I really have no idea what’s going on. Is there something more needed for this to work? I assumed not overriding VST3ClientExtensions::getCompatibleParameterIds() would just result in state being messed up, am I wrong?

Please check out the develop branch, we’ve added a new preprocessor definition JUCE_VST3_COMPONENT_CLASS this should be defined as a quoted string containing 32 hex characters representing the the class ID you want to use VST3: Add support for defining a custom VST3 component class ID · juce-framework/JUCE@1294562 · GitHub

1 Like

Awesome, that works great! Thank you.

2 Likes

I am TRYING to get this to work but somehow the result I see in Steinberg’s validator is not what I have defined. But the root of the issue for me is: a plugin that previously was built with JUCE 6.1.4 now has a different class ID when built with the very latest JUCE, even though plugin and manufacturer code have definitely not changed. I couldn’t find any breaking changes that would have caused this, so what could be going on? Obviously this kills backwards compatibility…?

EDIT: ah, it was another case of JUCE_VST3_CAN_REPLACE_VST2 having a different value now. Sorry… that is kind of a tricky one though…

Is it that JUCE_VST3_CAN_REPLACE_VST2 was enabled in your JUCE 6 version and wasn’t in the JUCE 8 version? Do you know why this value changed for you? i.e. are you saying JUCE caused the value to change or was this an error on your end?

As a side note if you have JUCE_VST3_CAN_REPLACE_VST2 enabled you probably also want to check the value of JUCE_FORCE_USE_LEGACY_PARAM_IDS, if this is enabled in both your old and new projects there is nothing more to do. If it isn’t enabled then you should get a warning on the latest version of JUCE explaining what to do next.

It was my mistake, I went through all the Projucer settings when setting everything up for JUCE8 and I thought “Why would I want this enabled, there was already a VST3 version of the plugin with JUCE6 so if a user still chose to use the VST2 there is probably a reason for it”, hence I disabled that setting. Not suspecting that this would cause the plugin ID to change, of course.

Thanks that’s useful to know. For what it’s worth one reason you might want to keep JUCE_VST3_CAN_REPLACE_VST2 enabled (ignoring the fact that it changes the ID) is if a user were ever to open some DAW session that was originally saved with the VST2 version. Or even if they wanted to load a preset that was originally saved in the DAW using the VST2 version, you would likely need it enabled.