Change VST3 "plugin name" if a JUCE plugin is used as a wrapper/VST3maker

Hi everybody,
I am working on a plugin that uses external modules. The plugin “wrapper/maker” can export the module as a VST3 so the name of the module has to change to be recognised as a different plugin by the host.
The procedure between VST2 and VST3 is very different. With VST2 it was possible but I struggle to understand how to pass the name of the module to the VST3 host like cubase. Cubase only sees one name, the name of the original module wrapper not the exported new VST3 instance from the module.

Can you please explain me how JUCE passes the name from the Projucer name field to the VST3 host and if it’s possible to change the name of the plugin from the inside of the “plugin maker” and not from the projucer field?

Thanks a lot for your answer
Damien

Hi, I did some tests and this is what I found.
The way VST2 and VST3 instances pass their name and manufacturer name to the host is different.

I don’t know if this is because of the loading sequence of the two types are different but in VST2 I can easily modify the plugin instance name from the inside with the class AudioProcessor::getName ( ) :

const String AudioProcessor::getName() const
{
return ("TheNewVstPluginName");
}

But for VST3 the name is not passed to the host with the same function.

It would require to override JucePlugin_Name and JucePlugin_Manufacturer from the AudioProcessor. Those details refers to the JUCE VST3 wrapper module juce_VST3_Wrapper.cpp:

        static const PClassInfo2 componentClass (JuceVST3Component::iid,
                                                 PClassInfo::kManyInstances,
                                                 kVstAudioEffectClass,
                                                 JucePlugin_Name,
                                                 JucePlugin_Vst3ComponentFlags,
                                                 JucePlugin_Vst3Category,
                                                 JucePlugin_Manufacturer,
                                                 JucePlugin_VersionString,
                                                 kVstVersionString);

I’m very interested to know why the name of the plugin instance can be easily modified from the AudioProcessor for VST2 and not for VST3.

Thanks a lot!

Damien

I’m very interested in something like this, too.
I want a user to be able to change the file name of my plugin and to have it appear under that name in the host.
I see that JucePlugin_Name is all over the place, and is set in JucePluginDefines.h . But - just checking - are you sure that this particular “componentClass” is where the host actually looks to get the name of the plugin? I’ve been unable to figure out where or how that happens.
My workaround was to build 16 instances of my plugin with 16 slightly different names, so a user can keep track of which is which, so they don’t see 16 plugins with the same name in the host.

1 Like

Hi Chuckk, concerning the vst3 instances, everything about the plugin naming and identification happens at the end of the juce_VST3_Wrapper.cpp. The component ID and GUID are calculated in the file modules/juce_audio_plugin_client/utility/juce_PluginUtilities.cpp

I still don’t know if it’s possible to dynamically override the different identifiers taken from projucer ( JucePlugin_Name, JucePlugin_Manufacturer…) used to define the plugin instance for the vst3 host.
If it was possible to override it from the audioprocessor.cpp that would be awesome, no need to hack the juce_VST3_Wrapper.cpp with new dynamically set variables.

Unfortunately I don’t have the c++ skills to do it, and I spent some time looking how the naming process happens and where it happens but cannot go further.

Maybe you could help with that?

If in audioprocessor.cpp we can declare:
“forget JucePlugin_Name static value from projucer and replace it from a xml key in an external xml file…” that would be so powerful for vst3 wrapper plugins. Same of course for all identifiers required.

Right now it’s the same deal for me, I have to compile as many instances from the projucer (with different IDs) that I produce variants which is not the fastest and most convenient way of course.

Have a nice weekend mate :wink:
Damien

I think dynamically changing the name will not help you much in terms of what the user can choose to select your plugin.
The information is collected during scanning, when your plugin is an empty shell, because no wrapped plugin is selected yet.
And the user will always just select an empty plugin to select something to wrap in a second step, when the plugin is already loaded.

You can change what getName() returns, and some hosts might change dynamically the title of a window. But I wouldn’t depend on it.

If you change it, you can experiment with updateHostDisplay(), however the ChangeDetails struct has no flag for name, so that’s not a good sign.

1 Like

Actually I work with CTRLR which is a software based on JUCE to design panels to control external gears (synth, fx …) via midi and sysex.
It can design custom panels with adding modulators etc on a canvas. The final step is to export an instance, either vst3, au or standalone of this very custom panel. So the final custom package contains the CTRLR plugin base, and the different extra files and details to build this custom plugin. This is why it’s almost like a wrapper in a way and have to get its naming from an external file and not from the base plugin itself.

It used to work before because of the simple VST2 naming process to host but the creator of CTRLR is MIA and since VST3 is the new standard we and the community have to update the program to be able to export instances with the custom midi panel identifiers. Right now when we export instances, the vst3 have the same name as the “wrapper” so any panel is identified in Cubase for exemple as CTRLR and not for exemple “JUNO106 Ctrlr”.
Ctrlr exports a xml file with all the custom modulators details AND of course this file contains the name of the panel, the plugin manufacturer name, the Unique ID is generated as well etc
So the best way for us would be to pass those identifiers to the host via juce_VST3_Wrapper.cpp by overriding the variables taken from projucer globals by the different identifiers located in the custom panel XML file.
It should be possible but as mentionned before, I don’t have enough skills to do that.

Actually, my plugin will be placed in a folder with the target plugin, and its filename changed to something similar, a macro based on the target plugin. Inside the processor constructor, the name of the target plugin is extracted from the name of the file and used to forward all relevant methods from the PluginInstance so that the host gets all the information from the target plugin. It mostly works so far. I got the idea from SAVIHost. So actually the user doesn’t load an empty plugin and select something to wrap after the plugin is loaded. The Processor constructor has access to the target plugin’s info during creation.
JucePlugin_Name, however, is a preprocessor macro, and, at least for my DAW, seems to be what determines how the plugin is named within the DAW (i.e. what the user sees when they choose which plugin to add to a track). That means that, if they use several copies of my plugin named after different wrapped plugins, they will all show up in the DAW with the same name.

One thing I tried a while back was to remove where the JucePlugin_Name macro is defined in JucePluginDefines.h, and to set JucePlugin_Name to something in the Processor constructor, as a const string or something. I don’t remember what errors it gave me. I’ll take another look tomorrow or Monday.

Oh okay I get your method, it makes sense.
Just as a reminder, identification for VST2 is different from VST3.
VST2 plugin identification was OS and host dependant. Some hosts just got the name from the plugin file name (yourPluginName.vst), some got the name in the info.plist (CFBundleName and NSHumanReadableCopyright for the author) on mac some got the name by simply calling the audioprocessor class getName() etc
For VST3 changing those parameters won’t suffice and won’t change the name of the plugin for the host. According to the VST3 sdk it requires the plugin name, the manufacturer name, manufacturer ID, the plugin unique 4 characters ID, the Component ID & Graphic ID (calculated with juce_PluginUtilities.cpp) , also the version of the plugin if I remember correctly. If you can declare those and pass them to the juce_VST3_Wrapper.cpp your host will identify the new plugin correctly.
Unfortunately those are defined by projucer at the preprocessor stage so hacking the juce_VST3_Wrapper.cpp and replacing the different variables would be the way unless the audioprocessor can override those variables but I doubt it’s possible. It was possible with getName() but it only passes the name of the plugin and not all the other identifiers.

The way the identification works within the host is the following:

  1. the host hits the juce_VST3_Wrapper
  2. the juce_VST3_Wrapper retrieves the preprocessor variables for identifications
    2note. (this is where we can hack it)
  3. the juce_VST3_Wrapper generates both CID and GID with juce_PluginUtilities.cpp
    4.juce_VST3_Wrapper passes the required identifiers to the host
  4. the host creates the instance et voilà

Keep me posted about all that, I’m very curious if you find a solution that would be awesome.

I will try something today. It’s not impossible to change JUCE code, but it would mean keeping a separate local copy or making a git fork. I did that once for something else, so I can do it again.
I believe it should be fine for my way; juce_VST3_Wrapper.cpp and juce_PluginUtilities.cpp are both used in the final executable, so they should also have access to the filename.
At what point does your custom XML file get taken into your executable?
I suppose you could simply change those two cpp files in your copy to load the XML and change the variables there, no?

You are right there’s nothing against changing those 2 JUCE files to dynamically update the variables from the xml. It’s just that I don’t know how to declare those variables and get them from the xml properly in c++. When I talk about the xml, I should say the panel valueTree. Not sure if they have to be defined from the audioprocessor or later, in the juce vst3 wrapper, or maybe as an extra.

If they are declared in the audioprocessor.cpp they would be something like (my syntax is wrong of course) :

JucePlugin_Name = ctrlrPlayerInstanceTree.getProperty(Ids::name).toString() 
JucePlugin_Manufacturer = ctrlrPlayerInstanceTree.getProperty(Ids::author).toString() 
and so on

Knowing that the xml ctrlrPlayerInstanceTree is called from the audioprocessor and holds all the required definitions for the custom panel (the extra layer of the base plugin).

Unfortunately this is where my skills fall short. I would need to go back to school to go a step further :slight_smile:

If you want to take a look at the ctrlr structure, here’s the link to the repo :

I managed to work this out for my plugin.

That PClassInfo2 struct at the end of juce_VST3_Wrapper.cpp is defined in ipluginbase.h; in VS, you can go there with a right click on PClassInfo2 and then Go To Definition.
A little down from the struct name, you have the constructor, with this signature:

PClassInfo2 (const TUID _cid, int32 _cardinality, const char8* _category, const char8* _name,
int32 _classFlags, const char8* _subCategories, const char8* _vendor, const char8* _version,
const char8* _sdkVersion)

That tells me that its use of JucePlugin_Name is const char8*, a pointer to char. This doesn’t matter normally because JucePlugin_Name is replaced everywhere as a string literal, so it just passes the name in quotes, which is accepted. But if you try to pass it a string, it’s an error. So I wrote a method to find the name of the binary and strip the extension, I added that method to juce::File.h and juce::File.cpp, and I can call it from the VST3 wrapper. I put a call to that function in place of the JucePlugin_Name macro, and cast it to character pointer, and it works. If I rename this vst3 file and rescan, it shows up on the list with its new filename.

I’m not so sharp with scanning XML, but if you can throw in a method to load your XML and extract the fields you need from it, you should be able to cast them to whatever type you need to fit the PClassInfo structure. The signature in ipluginbase.h tells you what types the parameters need to be.
Does that help you?

I spoke too soon. A host can only load one instance, I guess because I didn’t alter the ID parameters you mentioned.
I see “JucePlugin_PluginCode” referenced several times.

More:
I don’t think it will be simple to override these from an AudioProcessor. Is it going to work for you to modify a few Juce files?
I put some breakpoints on every instance of JucePlugin_Name that I could find in the code, and on debugging and scanning for plugins, the first one hit was indeed the VST3 wrapper file.

But there’s nothing stopping you from putting custom code into PluginUtilities.cpp and the VST3 wrapper file.

I’ve cloned your repository. Mind sharing a hint as to how you calculate the unique IDs?

1 Like

Hi Chuckk, you’ve come a long way already, you found where are located all the required variables and how they are linked together so you’re definitely on the right way!

I reall don’t care about modifying juce core in anyway if that allow vst3 working properly honnestly :slight_smile:

No worries, if you’re talking about the unique panel ID, for vst2, this ID is the one replacing and overriding the base unique plugin GUID from projucer, it’s automatically generated when a new panel is created with :

As you can see in the code, this generator generateRandomUniquePluginId() is also used for the manufacturer unique id as well. So you just need to search for this method you’ll see it’s called at several places. This 4 characters unique id should also be used as a base for the vst3 cid and gid in the juce_PluginUtilities.cpp instead of the static one from the preprocessor JucePlugin_PluginCode of course.

I really don’t mind adding new variables in the jucevst3wrapper to replace the stock ones :

JucePluginNameForHost
JucePluginManufacturerForHost
JucePlugin_ManufacturerCodeForHost
JucePlugin_VersionStringForHost
JucePlugin_PluginIdForHost
etc

and put them at the end of the Juce VST3 wrapper instead of :


JucePlugin_Name
JucePlugin_Manufacturer
JucePlugin_ManufacturerCode
JucePlugin_VersionString
JucePlugin_PluginCode
etc

They would each require a method to grab the key from the custom panel valuetree.

The method to call datas from the custom panel definitions tree is used several times with something like :

ctrlrPlayerInstanceTree.getProperty(Ids::panelAuthorName).toString());

it’s used here or exemple :

Let me know if you ever need something else, I don’t know if it could help with your own project but if you can do two birds one stone with CTRLR that would be awesome! Thanks a lot for your help Chuckk.