Issues with version integer reported by VST2

The answer to this particular concern is that, among the hosts that I have tested, only Cubase cares about actually showing a version number for each plug-in, and it shows it according to the return value of handleGetManufacturerVersion(), hence it will still show the correct version number as a result of the whole changes proposed here.

The other hosts that I have checked are REAPER, Presonus Studio One 3, Ableton Live and Cakewalk SONAR (on Windows), and none of them shows a version number for the plug-in that it lists.

These are the hosts that I have currently installed on my system, if someone else knows of some other host that shows the version number for plug-ins, Iā€™ll be happy to do some tests with that too.

@frankfilipanits You have been vocal about changing this and breaking compatibility. After reading through all of yfedeā€™s posts, do you see any technical reason for me to not go ahead with this? For me this does not seem to be ā€œjust another patchā€ on top of a bunch of other ā€œpatchesā€ - but carefully thought through by yfede.

@fabian, it seems that this has not gotten the intended attention.

now that 5.1.2 has just been released, what do you think of putting this change on develop, so that it will get the maximum amount of testing before the next advance of the master branch?

This way, if someone is unhappy about this change, it can be safely told to revert to official 5.1.2 version, develop branch is named like that for a reason, right?

I didnā€™t read all posts, but if i see that something

if (hostType.isSteinberg ())
{

should be the solution, for something sensitive like the version number (which may prevents loading the plugin at all), this is a very bad decision.
What happens if Steinberg renames its host-exectuable, and thousands plugins may not working anymoreā€¦

Well then how about we use a host callback to get the manufacturer instead:

// Returns empty string if the manufacturer host opcode is not available
String getHostManufacturer()
{
    if (hostCallback != nullptr)
    {
        char buffer[64 + 1];

        if (hostCallback (&vstEffect, hostOpcodeGetManufacturerName, 0, 0, buffer, 0) != 0)
            return String::fromUTF8 (buffer, 64 + 1);
    }

    return {};
}

For Steinberg products it returns ā€œSteinbergā€. I doubt they will ever change that.

I donā€™t have a good feeling about this all, a plugin gives a version number, which depends on the host.

(By the way, i donā€™t have a good felling about all host-specific changes, its a cat and mouse game)

Wouldnā€™t it be the cleaner solution, if the JUCE-team does some phone-calls with developer of the specific DAW, and solves this kind of problems forever, instead of fixing the symptom.

(Wouldnā€™t it ironic if a host tries to detect if a plugin is build with juce, and implements workarounds too :wink:

1 Like

@yfede What would happen if you would always execute the code inside the hostType.isSteinberg ()? Iā€™d rather remove that line and give JUCE users a flag to use the old JUCE version behaviour on old plug-ins. New plug-ins could then always use one of the encodings which works best with all hosts. What are your thoughts on this?

That would be quite meaningless, because that code is only there to juggle an otherwise perfectly good binary version number, in a way so that Cubase displays the correct version number when listing the plug-in. Reason is given further down in this post.

I found that Iā€™m usually in agreement with the conservative opinions exposed by @chkn throughout the forum, so I strongly believe that the sole reason why he doesnā€™t agree with my proposal above is because (by his own admission) he didnā€™t take the time to read and understand it thoroughly, and at the present moment he has a wrong impression about it.

To right that wrong impression, let me summarize the cornerstone of my PR, which is:

the binary version number defined in JucePlugin_VersionCode gets used everywhere ā€œas isā€, without being touched

My PR implements that, with only one, single, well defined and reasoned exception: the version number that is asked by Cubase for display only, gets manipulated so that Cubase displays the correct version number in its plug-in list.

Not even Cubase uses that version number for deciding whether to load plug-in state or not, and since that code only acts when Cubase is the DAW, there is no risk that the mangling affects other DAWs.

What if Steinberg decided to rename its executables? The only net effect is that you would see the wrong version number in its plug-in list which, I repeat, has nothing to do with plug-in state loading.

In contrast with the cornerstone of my PR explained above, the current JUCE code has the following risk: (see my first post in this topic).

If you have your plug-in version to 1.2.11, and then update it to version 1.3.1, your 1.3.1 version will fail to load the plug-in state saved with 1.2.11 in Cubase and Studio One.

This risk comes from a half-finished attempt of implementing what my PR really does: it is because JUCE applied a general solution (always manipulating the binary version number) for a very specific problem (Cubase does not show the correct version number in its list).

With my proposed implementation, this problem is resolved and the risk does not happen again.

What about plug-ins that were built with a version of JUCE where the problem was present?

In my last long post above, I demonstrated how merging my PR will not cause the binary version number of existing projects to decrease. Since its only the decrease which may cause a plug-in state not to be restored, by preventing a decrease in that value we avert the risk that a DAW refuses to load a plug-in state.

bump?

To summarize what all of the above is about in just one phrase:

the current JUCE implementation has a bug: if a plug-in is released with one number in its version greater than 10 (like 1.2.11), then a subsequent version (like 1.3.0) will not be fed the saved session data in Cubase and Studio One projects

Sorry @yfede, for losing the ball on this. Youā€™ve done some incredible investigation work here and the JUCE team will definitely commit something to fix the bug you describe. It definitely is a bug!

Iā€™m really not trying to make your life hard but just want to be absolutely sure that whatever we commit is really the best thing to do.

I agree somewhat with @chkn that it seems odd to have host-specific behaviour with something as important as the version number. I understand that Steinberg specific code is only there for the way the version number is displayed - however, I feel that Cubase should be the gold-standard of hosts and that your encoding table should be the reference for all hosts should they ever display the version number.

Thus, isnā€™t removing the if (hostType.isSteinberg ()) more future-proof? If other hosts start displaying the version wouldnā€™t they also use your encoding table to do this?

Ah, I understand your thinking now.

Well, personally I donā€™t believe that some other DAW will end up implementing the decoding of the version number exactly according to that table, because basically it is not documented anywhere: the official VST2 documentation does not provide insights about what the intended encoding of that version number should be.
In absence of such a reference, the only way for a developer to implement it the exact same way as Cubase is to reverse engineer it, as I did, and at that point, Iā€™m afraid it is much easier to decide not to display the version number. Which may explain why no other DAW currently seem to bother about it.

In that sense, I see your point: regarding the ā€˜ifā€™:

  • If it is there, it means that Cubase is treated as a ā€œspecial caseā€
  • If it is NOT there, it means that that algorithm is regarded more or less as a de-facto standard

but since Cubase seems to be the only DAW that makes use of it, it is irrelevant which of the two cases above is true.

So, I agree about the removal of the ā€œif (isSteinberg())ā€ but perhaps Iā€™d do that by commenting it out rather than by removing it completely.

A short note could also be added in its proximity, like:

Only Cubase seems to be using the value that is being calculated here, so we now treat this encoding algorithm as the de-facto standard. If it turns out that other DAWs use different algorithms, you may need to uncomment the ā€˜ifā€™ below and/or write a similar one for all the other DAWs that need to be supported

How does that sound for you?

Yeah that sounds good. Iā€™ll add this at the beginning of next week.

2 Likes

OK this is now fixed on develop with commit c382827. Iā€™ve also added the encoding to the hosting code so that JUCE hosts will display a version number string consistent with what Cubase displays.

Iā€™ve also contacted a few major DAW vendors and made them aware of the encoding table that you posted. Should any other DAW apart from Cubase ever choose to display the version number in a human readable string, Iā€™m hoping they will use @yfedeā€™s table.

Once again, thank you for your work on this @yfede.

7 Likes

Thank you for double-checking this thoroughly and finally deciding to incorporate it :slight_smile:

ā€¦and how do we warn developers that certain version numbers canā€™t be represented whatsoever, because of limitations that are inherent in Cubaseā€™s encoding algorithm?

I think compiler warnings are the right tool here, so a snippet of code like this, added to juce_CheckSettingMacros.h, catches the issue and gives the necessary information:

#if JucePlugin_Build_VST

 #if JucePlugin_VersionCode < 0x010000   // Major < 0

  #if (JucePlugin_VersionCode & 0x00FF00) > (9 * 0x100) // check if Minor number exceeeds 9
   #warning When version has "major" = 0, VST2 has trouble displaying "minor" exceeding 9
  #endif

  #if (JucePlugin_VersionCode & 0xFF) > 9   // check if Bugfix number exceeeds 9
   #warning When version has "major" = 0, VST2 has trouble displaying "bugfix" exceeding 9
  #endif

 #elif JucePlugin_VersionCode >= 0x650000   // Major >= 101

  #if (JucePlugin_VersionCode & 0x00FF00) > (99 * 0x100) // check if Minor number exceeeds 99
   #warning When version has "major" > 100, VST2 has trouble displaying "minor" exceeding 99
  #endif

  #if (JucePlugin_VersionCode & 0xFF) > 99  // check if Bugfix number exceeeds 99
   #warning When version has "major" > 100, VST2 has trouble displaying "bugfix" exceeding 99
  #endif

 #endif // JucePlugin_VersionCode

#endif // JucePlugin_Build_VST

Iā€™ve also considered adding assertions in the VST wrapper, but thatā€™s not ideal because they may not be hit if one doesnā€™t usually run the VST for debugging.
Think of a very small change, one may bump the version number even without bothering of running all formats in the debugger, and the new version number may silently ā€œbreakā€ the rules for being displayed correctly.

Plus, assertions are blocking and, given how small consideration is currently given by DAWs to the VST2 version number to display, a compiler warning seems more reasonable than something that blocks your debugging.

Adding a check in the Projucer is even worse, because that will go unnoticed by all the people, like me, who donā€™t use it if not to bootstrap projects, sometimes.

1 Like

Gentle bump for @fabian, to bring his attention to my post above, regarding how to warn developers that they are using a ā€œdangerousā€ version number, which risks of not being displayed correctly.

Thanks. This will appear on develop shortly.

Is this still relevant in 2024?