Ok, I’ve worked this out.
Let’s call VERSION_CODE the number that is returned by the VST2 plug-in to inform about its version.
That is the number expected to be returned by the AudioEffectX::getVendorVersion() method, which is handled/implemented by handleGetManufacturerVersion() in the JUCE VST2 wrapper.
Ok, let’s state my simpler finding first: both Cubase and Studio One 3 don’t feed the chunk stored in the session if the plug-in VERSION_CODE is lower than the one emitted by the same plug-in when the session was saved.
If the VERSION_CODE is equal or higher, it is passed to the plug-in the usual way.
A simple numerical comparison takes place in this case, and VERSION_CODE is treated as a simple integer.
In this context, no interpretation of which part represents Major, Minor and Bugfix version number is performed: the comparison is plain arithmetic.
This may seem obvious for now, but that’s not really that obvious when you see how “strange” the following is.
Of all the hosts I have tested, Cubase is the only one which also attempts to display a version number for the plug-in, inferring it from that plain VERSION_CODE integer, and that’s where madness begins.
Probably because the VST2 does not specify a format for encoding Major, Minor, Bugfix (and even Build) in that VERSION_CODE, I guess various developers followed different conventions and Cubase tries its best to make sense of them all.
What I found by attempting with various VERSION_CODE values is the following:
-
Encoding A: when in the range [0, 9], the value is interpreted as a Major version number. All the following dot values are 0. value 1 corresponds to “1.0.0.0”, 2 to “2.0.0.0” and so on.
-
Encoding B: when in the range [10, 9999], each decimal digit of the value is treated as a dot component, meaning that the number 1234 is interpreted as “1.2.3.4”
-
Encoding C: when in the range [10000, 65535 (0xFFFF)], the four most significant decimal digits are treated as the dot components. The digit for the units, which is the fifth, is ignored.
12345 is shown as “1.2.3.4” -
Encoding D: when in the range [0x10000 (65536), 0x64FFFF], the three bytes that compose the hexadecimal representation of the number are treated as the three most significant dot parts, leaving the fourth always at 0.
0x010203 corresponds to 1.2.3.0.
Note that 0x64 is 100, so the highest major version number for this representation is 100. -
Encoding E: when in the range [0x650000, MAX_INT] the digits of the decimal representation of the number are treated as follows: MMMmmBBbbb, where MMM, mm, BB, bbb are the four dot components.
(I made up the letters for the different encodings, it’s not like they are documented anywhere at all)
So, in the end what should be done?
My personal suggestion is this: because the JucePlugin_VersionCode is natively in Encoding D, that is the encoding that should be used (whenever possible) to report the value to be displayed to Cubase.
I added “whenever possible” because “Encoding D” cannot be effectively used to represent all version numbers, in particular version numbers that start with “0.”
For example, expressing “0.1.0” in Encoding D yields 0x000100, which is decimal 256.
The problem is that the value 256 falls in the range of values that are interpreted according to Encoding B, giving “0.2.5.6”.
So, my complete proposal is implemented as follows:
static inline int32 convertHexVersionToDecimal (const unsigned int hexVersion)
{
#if JUCE_VST_RETURN_HEX_VERSION_NUMBER_DIRECTLY
return (int32) hexVersion;
#else
const int32 major = (hexVersion >> 16) & 0xff;
const int32 minor = (hexVersion >> 8) & 0xff;
const int32 bugfix = hexVersion & 0xff;
if (major < 1) // in this case attempt to use Encoding B, with assertions for values out of range
{
jassert (minor <= 9);
jassert (bugfix <= 9);
return major * 1000 + minor * 100 + bugfix * 10;
}
if (major > 100) // in this case attempt to use Encoding E, with assertions for values out of range
{
jassert (minor <= 99);
jassert (bugfix <= 99);
return major * 10000000 + minor * 100000 + bugfix * 1000;
}
return hexVersion; // in all other cases, Encoding D well represents the value.
#endif
}
(Disclaimer: I haven’t compiled this code yet, it’s to be treated as pseudo-code)
I have left in there the JUCE_VST_RETURN_HEX_VERSION_NUMBER_DIRECTLY to allow developers that already have resolved this in their own ways to override the default behavior, and the default behavior is such that is still a monotonic function whose outcome increases when the JucePlugin_VersionCode increases.
For all cases where the native encoding of JucePlugin_VersionCode cannot be used, assertions are in place to ensure that the dot parts of the version number are within the desired limits.

