How to get VST3 Class-ID (aka CID, aka Component-ID)

I am working on an app that hosts and configures VSTs, and I’m looking into exporting session from my software to other DAW formats.

I need to access the VST3 ClassID (The GUID that uniquely identifies a VST type)

If my understanding is correct, Class IDs are 128 bits or 16 bytes long.
juce::PluginDescription::uid is an int, so it cannot (and does not) store the full ClassID for VST3 plugins.

Is there a way to get extract the VST3 ClassID from either a juce::PluginDescription or a Steinberg::Vst::IComponent?

Many thanks for any pointers!

Edit: It looks like in order to do this for kDistributed (aka “Split”) VST3 plugins I need to get a pointer to the Vst::IEditController for a given plugin. ExternalPlugin::getPlatformSpecificData only grants access to the Vst::IComponent. Is it not possible to access the Vst::IEditController?

It’s certainly possible although I suspect you’re going to go through a lot of hair pulling working out the VST3 SDK includes into your project!

Assuming that’s no barrier, you can use the COM functions to get the IEditController. The VST3 hosting code does this in VST3ComponentHolder::fetchController() if you need an example.

From what I understand - if you’re after the FUID, I’m pretty sure you need to get the PClassInfo from the IPluginFactory. I don’t see a way of fetching the factory from the IComponent itself…

I don’t mind using the VST3 SDK, but AFAICT, JUCE’s interface hides all access to the underlying VST3 components, and it’s not possible to access anything other than the Vst::IComponent, which can be retrieved with getPlatformSpecificData(). On some plugins, the IComponent is the IEditController, but Steinberg discourages plugin developers from writing their plugins this way.

I would love to be wrong about this, but it looks to me like there is no way to access a VST3 plugin’s ClassID OR IEditController without modifying the underlying JUCE code. Please let me know if this is incorrect!

The VST3PluginInstance class is declared in a .cpp file and has no .h file, so none of its methods are available. This is also the case for VST3ComponentHolder.

JUCE hashes the 128 bit VST3 ClassIDs, and only stores the 32 bit hash in the PluginDescription.

For my purposes, I could probably extract what I need from a .vstpreset file, however it doesn’t look like it is possible to save a .vstpreset with JUCE. VST3PluginFormat has a the setStateFromVSTPresetFile helper for reading .vstpreset data, but no helper for writing .vstpreset data.

.vstpreset files include the Vst::IEditController state, so its also not possible to actually create a .vstpreset without access to the plugin’s VST::IEditController.

Hi @audioishi, I’m currently thinking about ways that we can expose some small, useful parts of the VST3 implementation. Would you mind providing a few more details about what you’re trying to achieve here?

There are requests in this thread for access to both the Component CID and the IEditController. Do you actually need access to these things, or would some higher-level functionality suffice? That is, if we added the ability to write a vstpreset file from an AudioPluginInstance, would that be an acceptable solution?

Thanks @reuk! My software includes exporters to to different DAW session file formats. To save a accurate DAW session file, I need to access the full VST3 state for each VST3 plugin instance in the session. This includes:

  • The full 128 bit Component ID (The VST3 SDK docs inconsistently refer to this value by 3 different names: ClassID, CID and ComponentID)
  • The state retrieved from the IEditController
  • The state retrieved from the IComponent

For folks coming from google, the Persistence section of the VST3 FAQ lightly touches on this.

For my purposes, I don’t need pointers to the IComponent and IEditController; I just need to be able to retrieve their state.

If there were a way to to save a VST3 preset blob, I could parse the blob, and manually extract the CID and both state chunks. But it would be ideal if there were something like vst3PluginInstance.getIEditControllerState() and .getIComponentState() in addition to some way to access the full CID.

Thanks, that’s helpful. At the moment, I’m leaning towards providing a MemoryBlock getStateForVSTPresetFile() function in JUCE which would allow writing vstpreset-formatted data into a MemoryBlock. This would have matching inverse behaviour to the existing setStateFromVSTPresetFile() function.

With such a function in place, I think it would be possible to read this MemoryBlock back into a Steinberg::Vst::PresetFile and to extract the bits and pieces that you need using getClassID and getEntry. Although this would be a ‘manual’ process, I think the code to do it already exists in the VST3 SDK. Would such a solution work for you?

Yep, that would be great. Thanks a lot.

Nice, that’s great. I have a proof-of-concept solution ready, so hopefully I’ll be able to make this public at some point next week, once it’s been reviewed and tested a bit more thoroughly.

1 Like

Thanks for your patience. I’ve merged this feature now:

To get at the VST3-internal preset data, you can pass an instance of ExtensionsVisitor to AudioPluginInstance::getExtensions. On the ExtensionsVisitor you can override visitVST3Client, and then call getPreset on the argument to that function.

Hopefully that all makes sense. Please let us know if you have any questions or run into any problems.

4 Likes

@reuk Great news! Thank you :slight_smile:

Awesome to have that interface to the wrapper internals now! :slight_smile:

Any technical reason why the VST3Client does not allow access to the edit controller pointer? This should now be possible as far as I can see. Or did I miss something?

I don’t think there’s a technical reason, but I’m reluctant to expose too much of the wrapper internals. The more we expose, the more we limit our options for refactoring/reimplementation in the future.

Perhaps the queryIEditController function already provides the functionality you need. Otherwise, it would be useful to know more about your use-case so that the team can evaluate whether allowing direct access to the edit controller pointer is really the best solution.

Ok, I see.

For my use case I want to get a list of all the VST3 parameter IDs of a hosted plugin and this is only accessible from the edit controller and not from the component.

As I am the host I cannot use queryIEditController. As far as I can see this is meant to get an edit controller instance inside a VST3 plugin, right?

I fear, I do not really understand, how this visitor pattern should be used…

I have code which is like:
AEffect* pAEffect = dynamic_cast<AEffect*>(reinterpret_cast<AEffect*>(pWrappedAudioPluginInstance->getPlatformSpecificData()));
which now (with Juce 6.1.2) gives me a deprecated warning.
How could/should I write that code, so that I have access to ‘VSTClient::getAEffectPtr()’?
A short example would be very welcome. Thanks!

In your case, I think the expected usage is something like this:

struct Visitor : public juce::ExtensionsVisitor
{
    void visitUnknown         (const Unknown&)         override {}
    void visitVST3Client      (const VST3Client&)      override {}
    void visitVSTClient       (const VSTClient& c)     override { pAEffect = c.getAEffectPtr(); }
    void visitAudioUnitClient (const AudioUnitClient&) override {}

    AEffect* pAEffect = nullptr;
};

Visitor visitor;
pWrappedAudioPluginInstance->getExtensions (visitor);
auto* pAEffect = visitor.pAEffect;
1 Like

That was a quick reply!
Thanks a lot! Now I understand.