From 1294562075528b2fe836a6d7891afee410535913 Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Tue, 14 Oct 2025 09:29:39 +0100 Subject: [PATCH] VST3: Add support for defining a custom VST3 component class ID --- .../utilities/juce_VST3ClientExtensions.h | 34 +++++- .../utilities/juce_VST3Interface.h | 108 ++++++++++-------- 2 files changed, 92 insertions(+), 50 deletions(-) diff --git a/modules/juce_audio_processors_headless/utilities/juce_VST3ClientExtensions.h b/modules/juce_audio_processors_headless/utilities/juce_VST3ClientExtensions.h index 2a1c846cf9..f8dee62a71 100644 --- a/modules/juce_audio_processors_headless/utilities/juce_VST3ClientExtensions.h +++ b/modules/juce_audio_processors_headless/utilities/juce_VST3ClientExtensions.h @@ -220,10 +220,42 @@ private: }; #if DOXYGEN + /** An optional user defined preprocessor definition for declaring the VST3 + plugin identifier as used by the host. + + This is useful if you're creating a VST3 plugin using JUCE that needs to + replace a VST3 plugin that was not originally created using JUCE. + + If there are multiple identifiers this plugin needs to replace take a look + at JUCE_VST3_COMPATIBLE_CLASSES. If required, both preprocessor definitions + can be used in combination for maximum compatibility. + + The definition of this preprocessor must be defined at the project + level, normally in your CMake or Projucer project files. + + If JUCE_VST3_CAN_REPLACE_VST2 is enabled, the VST3 plugin will have the + same identifier as the VST2 plugin and therefore this preprocessor + definition will have no effect! + + This preprocessor definition should be defined as a string containing 32 + hex characters, for example... + + @code + JUCE_VST3_COMPONENT_CLASS="0F1E2D3C4B5A69788796A5B4C3D2E1F0" + @endcode + + @see JUCE_VST3_COMPONENT_CLASS + */ + #define JUCE_VST3_COMPONENT_CLASS + /** An optional user defined preprocessor definition for declaring a comma separated list of VST2 and VST3 plugin identifiers that this VST3 plugin can replace in a DAW session. + At the time of writing not all hosts support this feature, if you don't + have multiple plugins with different identifiers already released, consider + using JUCE_VST3_COMPONENT_CLASS instead. + The definition of this preprocessor must be defined at the project level, normally in your CMake or Projucer project files. @@ -265,7 +297,7 @@ private: If the parameter IDs between compatible versions differ VST3ClientExtensions::getCompatibleParameterIds() should also be overridden. - @see VST3Interface VST3ClientExtensions::getCompatibleParameterIds() + @see JUCE_VST3_COMPONENT_CLASS, VST3Interface, VST3ClientExtensions::getCompatibleParameterIds() */ #define JUCE_VST3_COMPATIBLE_CLASSES #endif // DOXYGEN diff --git a/modules/juce_audio_processors_headless/utilities/juce_VST3Interface.h b/modules/juce_audio_processors_headless/utilities/juce_VST3Interface.h index 110bed2e41..c1dfb4504f 100644 --- a/modules/juce_audio_processors_headless/utilities/juce_VST3Interface.h +++ b/modules/juce_audio_processors_headless/utilities/juce_VST3Interface.h @@ -117,18 +117,76 @@ struct VST3Interface return iid; } + /** Converts a 32-character hex notation string to a VST3 interface ID. + + @see jucePluginId, vst2PluginId + */ + static inline Id hexStringToId (const char* hex) + { + jassert (std::strlen (hex) == 32); + + const auto getByteValue = [](const char* str) + { + const auto getCharacterValue = [](const char c) + { + if (c >= '0' && c <= '9') + return (std::byte) (c - '0'); + + if (c >= 'A' && c <= 'F') + return (std::byte) (c - 'A' + 10); + + if (c >= 'a' && c <= 'f') + return (std::byte) (c - 'a' + 10); + + // Invalid hex character! + jassertfalse; + return std::byte{}; + }; + + return getCharacterValue (str[0]) << 4 + | getCharacterValue (str[1]); + }; + + return { getByteValue (hex), + getByteValue (hex + 2), + getByteValue (hex + 4), + getByteValue (hex + 6), + getByteValue (hex + 8), + getByteValue (hex + 10), + getByteValue (hex + 12), + getByteValue (hex + 14), + getByteValue (hex + 16), + getByteValue (hex + 18), + getByteValue (hex + 20), + getByteValue (hex + 22), + getByteValue (hex + 24), + getByteValue (hex + 26), + getByteValue (hex + 28), + getByteValue (hex + 30) }; + } + /** Returns a 16-byte array indicating the VST3 interface ID used for a given JUCE VST3 plugin. Internally this is what JUCE will use to assign an ID to each VST3 interface, unless JUCE_VST3_CAN_REPLACE_VST2 is enabled. - @see vst2PluginId, hexStringToId + If JUCE_VST3_COMPONENT_CLASS is defined it will return this value when the + interface type is Type::component. This is useful if you're releasing a + VST3 plugin with JUCE that needs to replace a version of a VST3 plugin + that wasn't originally built using JUCE. + + @see vst2PluginId, hexStringToId, JUCE_VST3_COMPONENT_CLASS */ static inline Id jucePluginId (uint32_t manufacturerCode, uint32_t pluginCode, Type interfaceType = Type::component) { + #ifdef JUCE_VST3_COMPONENT_CLASS + if (interfaceType == Type::component) + return hexStringToId ( JUCE_VST3_COMPONENT_CLASS ); + #endif + const auto word0 = std::invoke ([&]() -> uint32_t { switch (interfaceType) @@ -194,54 +252,6 @@ struct VST3Interface }; } - /** Converts a 32-character hex notation string to a VST3 interface ID. - - @see jucePluginId, vst2PluginId - */ - static inline Id hexStringToId (const char* hex) - { - jassert (std::strlen (hex) == 32); - - const auto getByteValue = [](const char* str) - { - const auto getCharacterValue = [](const char c) - { - if (c >= '0' && c <= '9') - return (std::byte) (c - '0'); - - if (c >= 'A' && c <= 'F') - return (std::byte) (c - 'A' + 10); - - if (c >= 'a' && c <= 'f') - return (std::byte) (c - 'a' + 10); - - // Invalid hex character! - jassertfalse; - return std::byte{}; - }; - - return getCharacterValue (str[0]) << 4 - | getCharacterValue (str[1]); - }; - - return { getByteValue (hex), - getByteValue (hex + 2), - getByteValue (hex + 4), - getByteValue (hex + 6), - getByteValue (hex + 8), - getByteValue (hex + 10), - getByteValue (hex + 12), - getByteValue (hex + 14), - getByteValue (hex + 16), - getByteValue (hex + 18), - getByteValue (hex + 20), - getByteValue (hex + 22), - getByteValue (hex + 24), - getByteValue (hex + 26), - getByteValue (hex + 28), - getByteValue (hex + 30) }; - } - VST3Interface() = delete; };