diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 0fddbf7694..88f5a1bda3 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -37,6 +37,27 @@ The Javascript implementation increases compilation times while being required by only a select number of projects. +## Change + +The return type for VST3ClientExtensions::getCompatibleClasses() has changed +from a String to an array of 16 bytes. + +**Possible Issues** + +Any inherited classes overriding this method might fail to compile. + +**Workaround** + +Either explicitly switch to creating a 16-byte std::array or use +VST3ClientExtensions::toInterfaceId() to convert a string to a 16-byte array. + +**Rationale** + +As part of adding functionality to support migrating parameter IDs from +compatible plugins it was useful to switch to a safer type for representing +VST3 interface IDs that closer matches the VST3 SDK types. + + ## Change The VBlankAttachment class' inheritance from the ComponentPeer::VBlankListener diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt index 62f2831a24..23f6137865 100644 --- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt +++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt @@ -860,6 +860,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" @@ -3455,6 +3456,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj index 377388730c..9247d2cf1c 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj @@ -1095,6 +1095,9 @@ true + + true + true diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters index 6f25f4f2bb..25877052c3 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters @@ -1804,6 +1804,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj index 0aa583c9d3..d97ebc4639 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj @@ -1095,6 +1095,9 @@ true + + true + true diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters index 730cd91e51..c1ba09e988 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters @@ -1804,6 +1804,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt index 34171f6197..f9d6992c03 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt @@ -815,6 +815,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" @@ -3070,6 +3071,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj index 435dc4331a..e64a688c9c 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj @@ -1055,6 +1055,9 @@ true + + true + true diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters index 7a475a3df1..b05a019507 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters @@ -1594,6 +1594,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt index 35e7501e7e..a88bfc6b68 100644 --- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt @@ -848,6 +848,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" @@ -3256,6 +3257,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj index f44f8ff9db..c37d716ce5 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj @@ -1063,6 +1063,9 @@ true + + true + true diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters index c5886faeb6..957d187b47 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters @@ -1669,6 +1669,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj index e68c5fab18..b28adb2059 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj @@ -1063,6 +1063,9 @@ true + + true + true diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters index aad4602684..5e4d2e64e9 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters @@ -1669,6 +1669,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt index e46ad7a010..be29f69e17 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt @@ -819,6 +819,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" @@ -3154,6 +3155,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/utilities/juce_RangedAudioParameter.h" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST2ClientExtensions.h" + "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp" "../../../../../modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj index 761d9fbd53..56d8b7707e 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj @@ -1055,6 +1055,9 @@ true + + true + true diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters index f3ddc3d536..b954c7a5de 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters @@ -1624,6 +1624,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj index d7db6fd365..6451d6a7fc 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj @@ -1071,6 +1071,9 @@ true + + true + true diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters index 399197e763..3082400365 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1717,6 +1717,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj index 84f1c9922d..7a0e63f8eb 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj @@ -1071,6 +1071,9 @@ true + + true + true diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters index 97053ec167..182b38de9c 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -1717,6 +1717,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj index 0ce5ac00ff..28d7d579de 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj @@ -1054,6 +1054,9 @@ true + + true + true diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters index b6dcc7091b..343fe5911f 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters @@ -1621,6 +1621,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h index 1e7744f94c..ca2193dd96 100644 --- a/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h +++ b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h @@ -66,88 +66,6 @@ struct PluginUtilities return hostType; } - // NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code. - static void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16]) - { - #if JUCE_WINDOWS - const auto juce_sprintf = [] (auto&& head, auto&&... tail) { sprintf_s (head, (size_t) numElementsInArray (head), tail...); }; - const auto juce_strcpy = [] (auto&& head, auto&&... tail) { strcpy_s (head, (size_t) numElementsInArray (head), tail...); }; - const auto juce_strcat = [] (auto&& head, auto&&... tail) { strcat_s (head, (size_t) numElementsInArray (head), tail...); }; - const auto juce_sscanf = [] (auto&&... args) { sscanf_s (args...); }; - #else - const auto juce_sprintf = [] (auto&& head, auto&&... tail) { snprintf (head, (size_t) numElementsInArray (head), tail...); }; - const auto juce_strcpy = [] (auto&&... args) { strcpy (args...); }; - const auto juce_strcat = [] (auto&&... args) { strcat (args...); }; - const auto juce_sscanf = [] (auto&&... args) { sscanf (args...); }; - #endif - - char uidString[33]; - - const int vstfxid = (('V' << 16) | ('S' << 8) | (forControllerUID ? 'E' : 'T')); - char vstfxidStr[7] = { 0 }; - juce_sprintf (vstfxidStr, "%06X", vstfxid); - - juce_strcpy (uidString, vstfxidStr); - - char uidStr[9] = { 0 }; - juce_sprintf (uidStr, "%08X", JucePlugin_VSTUniqueID); - juce_strcat (uidString, uidStr); - - char nameidStr[3] = { 0 }; - const size_t len = strlen (JucePlugin_Name); - - for (size_t i = 0; i <= 8; ++i) - { - juce::uint8 c = i < len ? static_cast (JucePlugin_Name[i]) : 0; - - if (c >= 'A' && c <= 'Z') - c += 'a' - 'A'; - - juce_sprintf (nameidStr, "%02X", c); - juce_strcat (uidString, nameidStr); - } - - unsigned long p0; - unsigned int p1, p2; - unsigned int p3[8]; - - juce_sscanf (uidString, "%08lX%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X", - &p0, &p1, &p2, &p3[0], &p3[1], &p3[2], &p3[3], &p3[4], &p3[5], &p3[6], &p3[7]); - - union q0_u { - uint32 word; - uint8 bytes[4]; - } q0; - - union q1_u { - uint16 half; - uint8 bytes[2]; - } q1, q2; - - q0.word = static_cast (p0); - q1.half = static_cast (p1); - q2.half = static_cast (p2); - - // VST3 doesn't use COM compatible UUIDs on non windows platforms - #if ! JUCE_WINDOWS - q0.word = ByteOrder::swap (q0.word); - q1.half = ByteOrder::swap (q1.half); - q2.half = ByteOrder::swap (q2.half); - #endif - - for (int i = 0; i < 4; ++i) - uuid[i+0] = q0.bytes[i]; - - for (int i = 0; i < 2; ++i) - uuid[i+4] = q1.bytes[i]; - - for (int i = 0; i < 2; ++i) - uuid[i+6] = q2.bytes[i]; - - for (int i = 0; i < 8; ++i) - uuid[i+8] = static_cast (p3[i]); - } - #if JucePlugin_Build_VST static bool handleManufacturerSpecificVST2Opcode ([[maybe_unused]] int32 index, [[maybe_unused]] pointer_sized_int value, @@ -158,9 +76,10 @@ struct PluginUtilities if ((index == (int32) ByteOrder::bigEndianInt ("stCA") || index == (int32) ByteOrder::bigEndianInt ("stCa")) && value == (int32) ByteOrder::bigEndianInt ("FUID") && ptr != nullptr) { - uint8 fuid[16]; - getUUIDForVST2ID (false, fuid); - ::memcpy (ptr, fuid, 16); + const auto uidString = VST3ClientExtensions::convertVST2PluginId (JucePlugin_VSTUniqueID, JucePlugin_Name, VST3ClientExtensions::InterfaceType::component); + MemoryBlock uidValue; + uidValue.loadFromHexString (uidString); + uidValue.copyTo (ptr, 0, uidValue.getSize()); return true; } #endif diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp index aa6b9800be..63045e3dbd 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST3.cpp @@ -38,6 +38,38 @@ //============================================================================== #if JucePlugin_Build_VST3 +#if JUCE_VST3_CAN_REPLACE_VST2 && ! JUCE_FORCE_USE_LEGACY_PARAM_IDS && ! JUCE_IGNORE_VST3_MISMATCHED_PARAMETER_ID_WARNING + + // If you encounter this error there may be an issue migrating parameter + // automation between sessions saved using the VST2 and VST3 versions of this + // plugin. + // + // If you have released neither a VST2 or VST3 version of the plugin, + // consider only releasing a VST3 version and disabling JUCE_VST3_CAN_REPLACE_VST2. + // + // If you have released a VST2 version of the plugin but have not yet released + // a VST3 version of the plugin, consider enabling JUCE_FORCE_USE_LEGACY_PARAM_IDS. + // This will ensure that the parameter IDs remain compatible between both the + // VST2 and VST3 versions of the plugin in all hosts. + // + // If you have released a VST3 version of the plugin but have not released a + // VST2 version of the plugin, enable JUCE_IGNORE_VST3_MISMATCHED_PARAMETER_ID_WARNING. + // DO NOT change the JUCE_VST3_CAN_REPLACE_VST2 or JUCE_FORCE_USE_LEGACY_PARAM_IDS + // values as this will break compatibility with currently released VST3 + // versions of the plugin. + // + // If you have already released a VST2 and VST3 version of the plugin you may + // find in some hosts when a session containing automation data is saved using + // the VST2 or VST3 version, and is later loaded using the other version, the + // automation data will fail to control any of the parameters in the plugin as + // the IDs for these parameters are different. To fix parameter automation for + // the VST3 plugin when a session was saved with the VST2 plugin, implement + // VST3ClientExtensions::getCompatibleParameterIds() and enable + // JUCE_IGNORE_VST3_MISMATCHED_PARAMETER_ID_WARNING. + + #error You may have a conflict with parameter automation between VST2 and VST3 versions of your plugin. See the comment above for more details. +#endif + JUCE_BEGIN_NO_SANITIZE ("vptr") #if JUCE_PLUGINHOST_VST3 @@ -97,23 +129,33 @@ JUCE_BEGIN_NO_SANITIZE ("vptr") namespace juce { -JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4310) -JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wall") - -#if JUCE_VST3_CAN_REPLACE_VST2 - static Steinberg::FUID getFUIDForVST2ID (bool forControllerUID) - { - Steinberg::TUID uuid; - detail::PluginUtilities::getUUIDForVST2ID (forControllerUID, (uint8*) uuid); - return Steinberg::FUID (uuid); - } -#endif - -JUCE_END_IGNORE_WARNINGS_MSVC -JUCE_END_IGNORE_WARNINGS_GCC_LIKE +using VST3InterfaceType = VST3ClientExtensions::InterfaceType; +using VST3InterfaceId = VST3ClientExtensions::InterfaceId; using namespace Steinberg; +static FUID toSteinbergUID (const VST3InterfaceId& uid) +{ + return FUID::fromTUID ((const char*) (uid.data())); +} + +static VST3InterfaceId toVST3InterfaceId (const TUID uid) +{ + VST3InterfaceId iid; + std::memcpy (iid.data(), uid, iid.size()); + return iid; +} + +static VST3InterfaceId getInterfaceId (VST3InterfaceType interfaceType) +{ + #if JUCE_VST3_CAN_REPLACE_VST2 + if (interfaceType == VST3InterfaceType::controller || interfaceType == VST3InterfaceType::component) + return VST3ClientExtensions::convertVST2PluginId (JucePlugin_VSTUniqueID, JucePlugin_Name, interfaceType); + #endif + + return VST3ClientExtensions::convertJucePluginId (JucePlugin_ManufacturerCode, JucePlugin_PluginCode, interfaceType); +} + //============================================================================== #if JUCE_WINDOWS && JUCE_WIN_PER_MONITOR_DPI_AWARE double getScaleFactorForWindow (HWND); @@ -502,13 +544,15 @@ public: #if JUCE_FORCE_USE_LEGACY_PARAM_IDS return static_cast (paramIndex); #else + jassert (paramIndex < vstParamIDs.size()); return vstParamIDs.getReference (paramIndex); #endif } AudioProcessorParameter* getParamForVSTParamID (Vst::ParamID paramID) const noexcept { - return paramMap[static_cast (paramID)]; + const auto iter = paramMap.find (paramID); + return iter != paramMap.end() ? iter->second : nullptr; } AudioProcessorParameter* getBypassParameter() const noexcept @@ -561,8 +605,61 @@ public: bool isUsingManagedParameters() const noexcept { return juceParameters.isUsingManagedParameters(); } + std::map getParameterMap (const VST3InterfaceId& pluginId) const + { + const auto iter = compatibleParameterIdMap.find (pluginId); + return iter != compatibleParameterIdMap.end() ? iter->second + : std::map{}; + } + + AudioProcessorParameter* getParameter (const String& juceParamId) const + { + const auto iter = juceIdParameterMap.find (juceParamId); + return iter != juceIdParameterMap.end() ? iter->second : nullptr; + } + + void updateParameterMapping() + { + static const auto currentPluginId = getInterfaceId (VST3InterfaceType::component); + + compatibleParameterIdMap = {}; + compatibleParameterIdMap[currentPluginId] = paramMap; + + if (const auto* ext = audioProcessor->getVST3ClientExtensions()) + { + for (auto& compatibleClass : ext->getCompatibleClasses()) + { + auto& parameterIdMap = compatibleParameterIdMap[compatibleClass]; + + for (auto [oldParamId, newParamId] : ext->getCompatibleParameterIds (compatibleClass)) + { + auto* parameter = getParameter (newParamId); + parameterIdMap[oldParamId] = parameter; + + // This means a parameter ID returned by getCompatibleParameterIds() + // does not match any parameters declared in the plugin. All IDs must + // match an existing parameter, or return an empty string to indicate + // there is no parameter to map to. + jassert (parameter != nullptr || newParamId.isEmpty()); + + // This means getCompatibleParameterIds() returned a parameter mapping + // that will hide a parameter in the current plugin! If this is due to + // an ID collision between plugin versions, you may be able to determine + // the mapping to report based on setStateInformation(). If you've + // already done this you can safely ignore this warning. If there is no + // way to determine the difference between the two plugin versions in + // setStateInformation() the best course of action is to remove the + // problematic parameter from the mapping. + jassert (compatibleClass != currentPluginId + || getParamForVSTParamID (oldParamId) == nullptr + || parameter == getParamForVSTParamID (oldParamId)); + } + } + } + } + //============================================================================== - inline static const FUID iid { TUID INLINE_UID (0x0101ABAB, 0xABCDEF01, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::processor)); private: //============================================================================== @@ -570,7 +667,7 @@ private: { parameterGroups = audioProcessor->getParameterTree().getSubgroups (true); - #if JUCE_DEBUG + #if JUCE_ASSERTIONS_ENABLED_OR_LOGGED auto allGroups = parameterGroups; allGroups.add (&audioProcessor->getParameterTree()); std::unordered_set unitIDs; @@ -633,7 +730,8 @@ private: } vstParamIDs.add (vstParamID); - paramMap.set (static_cast (vstParamID), juceParam); + paramMap[vstParamID] = juceParam; + juceIdParameterMap[LegacyAudioParameter::getParamID (juceParam, false)] = juceParam; } auto numPrograms = audioProcessor->getNumPrograms(); @@ -650,7 +748,7 @@ private: programParamID = static_cast (i++); vstParamIDs.add (programParamID); - paramMap.set (static_cast (programParamID), ownedProgramParameter.get()); + paramMap[programParamID] = ownedProgramParameter.get(); } cachedParamValues = CachedParamValues { { vstParamIDs.begin(), vstParamIDs.end() } }; @@ -658,20 +756,13 @@ private: Vst::ParamID generateVSTParamIDForParam (const AudioProcessorParameter* param) { - auto juceParamID = LegacyAudioParameter::getParamID (param, false); + const auto juceParamID = LegacyAudioParameter::getParamID (param, false); - #if JUCE_FORCE_USE_LEGACY_PARAM_IDS + #if JUCE_FORCE_USE_LEGACY_PARAM_IDS return static_cast (juceParamID.getIntValue()); - #else - auto paramHash = static_cast (juceParamID.hashCode()); - - #if JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS - // studio one doesn't like negative parameters - paramHash &= ~(((Vst::ParamID) 1) << (sizeof (Vst::ParamID) * 8 - 1)); + #else + return VST3ClientExtensions::convertJuceParameterId (juceParamID, JUCE_USE_STUDIO_ONE_COMPATIBLE_PARAMETERS); #endif - - return paramHash; - #endif } //============================================================================== @@ -679,6 +770,8 @@ private: CachedParamValues cachedParamValues; Vst::ParamID bypassParamID = 0, programParamID = static_cast (paramPreset); bool bypassIsRegularParameter = false; + std::map> compatibleParameterIdMap; + std::map juceIdParameterMap; //============================================================================== std::atomic refCount { 0 }; @@ -686,7 +779,7 @@ private: //============================================================================== LegacyAudioParametersWrapper juceParameters; - HashMap paramMap; + std::map paramMap; std::unique_ptr ownedBypassParameter, ownedProgramParameter; Array parameterGroups; @@ -764,6 +857,7 @@ static void setValueAndNotifyIfChanged (AudioProcessorParameter& param, float ne class JuceVST3EditController final : public Vst::EditController, public Vst::IMidiMapping, public Vst::IUnitInfo, + public Vst::IRemapParamID, public Vst::ChannelContext::IInfoListener, #if JucePlugin_Enable_ARA public Presonus::IPlugInViewEmbedding, @@ -783,12 +877,7 @@ public: } //============================================================================== - - #if JUCE_VST3_CAN_REPLACE_VST2 - inline static const FUID iid = getFUIDForVST2ID (true); - #else - inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0x1234ABCD, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; - #endif + inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::controller)); //============================================================================== JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Winconsistent-missing-override") @@ -1028,6 +1117,30 @@ public: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgramChangeParameter) }; + //============================================================================== + tresult PLUGIN_API getCompatibleParamID (const TUID pluginToReplaceUID, + Vst::ParamID oldParamID, + Vst::ParamID& newParamID) override + { + const auto parameterMap = audioProcessor->getParameterMap (toVST3InterfaceId (pluginToReplaceUID)); + const auto iter = parameterMap.find (oldParamID); + + if (iter == parameterMap.end()) + { + // This suggests a host is trying to load a plugin and parameter ID + // combination that hasn't been accounted for in getCompatibleParameterIds(). + // Override this method in VST3ClientExtensions and return a suitable + // parameter mapping to silence this warning. + jassertfalse; + return kResultFalse; + } + + const auto* parameter = iter->second; + newParamID = parameter != nullptr ? audioProcessor->getVSTParamIDForIndex (parameter->getParameterIndex()) + : 0xffffffff; + return kResultTrue; + } + //============================================================================== tresult PLUGIN_API setChannelContextInfos (Vst::IAttributeList* list) override { @@ -1101,8 +1214,10 @@ public: } } + audioProcessor->updateParameterMapping(); + if (auto* handler = getComponentHandler()) - handler->restartComponent (Vst::kParamValuesChanged); + handler->restartComponent (Vst::kParamValuesChanged | Vst::kParamIDMappingChanged); return kResultOk; } @@ -1549,6 +1664,7 @@ private: UniqueBase{}, UniqueBase{}, UniqueBase{}, + UniqueBase{}, UniqueBase{}, SharedBase{}, UniqueBase{}, @@ -1557,6 +1673,9 @@ private: #endif SharedBase{}); + if (targetIID == Vst::IRemapParamID::iid) + jassertfalse; + if (result.isOk()) return result; @@ -2508,7 +2627,7 @@ private: return createARAFactory(); } - inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0xA1B2C3D4, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::ara)); private: //============================================================================== @@ -2581,11 +2700,7 @@ public: AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } //============================================================================== - #if JUCE_VST3_CAN_REPLACE_VST2 - inline static const FUID iid = getFUIDForVST2ID (false); - #else - inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0x9182FAEB, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; - #endif + inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::component)); JUCE_DECLARE_VST3_COM_REF_METHODS @@ -3998,15 +4113,7 @@ public: Array oldArray; for (const auto& uid : extensions->getCompatibleClasses()) - { - // All UIDs returned from getCompatibleClasses should be 32 characters long - jassert (uid.length() == 32); - - // All UIDs returned from getCompatibleClasses should be in hex notation - jassert (uid.containsOnly ("ABCDEF0123456789")); - - oldArray.add (uid); - } + oldArray.add (String::toHexString (uid.data(), (int) uid.size(), 0)); return oldArray; }()); @@ -4034,7 +4141,7 @@ public: return kNotImplemented; } - inline static const FUID iid { TUID INLINE_UID (0xABCDEF01, 0xC0DEF00D, JucePlugin_ManufacturerCode, JucePlugin_PluginCode) }; + inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::compatibility)); private: std::atomic refCount { 1 }; diff --git a/modules/juce_audio_processors/juce_audio_processors.cpp b/modules/juce_audio_processors/juce_audio_processors.cpp index 873ca3ade0..a3d5d7ed9e 100644 --- a/modules/juce_audio_processors/juce_audio_processors.cpp +++ b/modules/juce_audio_processors/juce_audio_processors.cpp @@ -231,6 +231,7 @@ private: #include "utilities/juce_PluginHostType.cpp" #include "utilities/juce_AAXClientExtensions.cpp" #include "utilities/juce_VST2ClientExtensions.cpp" +#include "utilities/juce_VST3ClientExtensions.cpp" #include "utilities/ARA/juce_ARA_utils.cpp" #include "format_types/juce_LV2PluginFormat.cpp" diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 74376b5096..103d303c12 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -1154,7 +1154,11 @@ public: See also the helper function getXmlFromBinary() for loading settings as XML. - @see setCurrentProgramStateInformation + VST3ClientExtensions::getCompatibleParameterIds() will always be called after + setStateInformation() therefore you can use information from the plugin state + to determine which parameter mapping to use if necessary. + + @see setCurrentProgramStateInformation, VST3ClientExtensions::getCompatibleParameterIds */ virtual void setStateInformation (const void* data, int sizeInBytes) = 0; diff --git a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp new file mode 100644 index 0000000000..b3cd133bb8 --- /dev/null +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp @@ -0,0 +1,167 @@ +/* + ============================================================================== + + This file is part of the JUCE framework. + Copyright (c) Raw Material Software Limited + + JUCE is an open source framework subject to commercial or open source + licensing. + + By downloading, installing, or using the JUCE framework, or combining the + JUCE framework with any other source code, object code, content or any other + copyrightable work, you agree to the terms of the JUCE End User Licence + Agreement, and all incorporated terms including the JUCE Privacy Policy and + the JUCE Website Terms of Service, as applicable, which will bind you. If you + do not agree to the terms of these agreements, we will not license the JUCE + framework to you, and you must discontinue the installation or download + process and cease use of the JUCE framework. + + JUCE End User Licence Agreement: https://juce.com/legal/juce-8-licence/ + JUCE Privacy Policy: https://juce.com/juce-privacy-policy + JUCE Website Terms of Service: https://juce.com/juce-website-terms-of-service/ + + Or: + + You may also use this code under the terms of the AGPLv3: + https://www.gnu.org/licenses/agpl-3.0.en.html + + THE JUCE FRAMEWORK IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL + WARRANTIES, WHETHER EXPRESSED OR IMPLIED, INCLUDING WARRANTY OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + + ============================================================================== +*/ + +namespace juce +{ + +std::map VST3ClientExtensions::getCompatibleParameterIds (const InterfaceId&) const +{ + return {}; +} + +VST3ClientExtensions::InterfaceId VST3ClientExtensions::convertJucePluginId (uint32_t manufacturerCode, + uint32_t pluginCode, + InterfaceType interfaceType) +{ + const auto word0 = std::invoke ([&]() -> uint32_t + { + switch (interfaceType) + { + case InterfaceType::ara: [[fallthrough]]; + case InterfaceType::controller: [[fallthrough]]; + case InterfaceType::compatibility: [[fallthrough]]; + case InterfaceType::component: return 0xABCDEF01; + case InterfaceType::processor: return 0x0101ABAB; + } + + jassertfalse; + return 0; + }); + + const auto word1 = std::invoke ([&]() -> uint32_t + { + switch (interfaceType) + { + case InterfaceType::ara: return 0xA1B2C3D4; + case InterfaceType::controller: return 0x1234ABCD; + case InterfaceType::compatibility: return 0xC0DEF00D; + case InterfaceType::component: return 0x9182FAEB; + case InterfaceType::processor: return 0xABCDEF01; + } + + jassertfalse; + return 0; + }); + + std::array data; + std::memcpy (&data[0], &word0, sizeof (word0)); + std::memcpy (&data[4], &word1, sizeof (word1)); + std::memcpy (&data[8], &manufacturerCode, sizeof (manufacturerCode)); + std::memcpy (&data[12], &pluginCode, sizeof (pluginCode)); + + return data; +} + +VST3ClientExtensions::InterfaceId VST3ClientExtensions::convertVST2PluginId (uint32_t pluginCode, + const String& pluginName, + InterfaceType interfaceType) +{ + VST3ClientExtensions::InterfaceId iid{}; + + iid[0] = (std::byte) 'V'; + iid[1] = (std::byte) 'S'; + iid[2] = (std::byte) std::invoke ([&] + { + switch (interfaceType) + { + case InterfaceType::controller: return 'E'; + case InterfaceType::component: return 'T'; + case InterfaceType::ara: [[fallthrough]]; + case InterfaceType::compatibility: [[fallthrough]]; + case InterfaceType::processor: break; + } + + // A VST2 plugin only has two interfaces + // - component (the audio effect) + // - controller (the editor/UI) + jassertfalse; + return '\0'; + }); + iid[3] = (std::byte) (pluginCode >> 24); + iid[4] = (std::byte) (pluginCode >> 16); + iid[5] = (std::byte) (pluginCode >> 8); + iid[6] = (std::byte) pluginCode; + + for (const auto [index, character] : enumerate (pluginName, (size_t) 7)) + { + if (index >= iid.size()) + break; + + iid[index] = (std::byte) CharacterFunctions::toLowerCase (character); + } + + #if JUCE_WINDOWS + std::swap (iid[0], iid[3]); + std::swap (iid[1], iid[2]); + std::swap (iid[4], iid[5]); + std::swap (iid[6], iid[7]); + #endif + + return iid; +} + +uint32_t VST3ClientExtensions::convertJuceParameterId (const String& parameterId, bool studioOneCompatible) +{ + auto hash = (uint32_t) (parameterId.hashCode()); + + if (studioOneCompatible) + hash &= 0x7fffffff; + + return hash; +} + +VST3ClientExtensions::InterfaceId VST3ClientExtensions::toInterfaceId (const String& interfaceIdString) +{ + jassert (interfaceIdString.length() == 32); + jassert (interfaceIdString.containsOnly ("0123456789abcdefABCDEF")); + + return { (std::byte) interfaceIdString.substring ( 0, 2).getHexValue32(), + (std::byte) interfaceIdString.substring ( 2, 4).getHexValue32(), + (std::byte) interfaceIdString.substring ( 4, 6).getHexValue32(), + (std::byte) interfaceIdString.substring ( 6, 8).getHexValue32(), + (std::byte) interfaceIdString.substring ( 8, 10).getHexValue32(), + (std::byte) interfaceIdString.substring (10, 12).getHexValue32(), + (std::byte) interfaceIdString.substring (12, 14).getHexValue32(), + (std::byte) interfaceIdString.substring (14, 16).getHexValue32(), + (std::byte) interfaceIdString.substring (16, 18).getHexValue32(), + (std::byte) interfaceIdString.substring (18, 20).getHexValue32(), + (std::byte) interfaceIdString.substring (20, 22).getHexValue32(), + (std::byte) interfaceIdString.substring (22, 24).getHexValue32(), + (std::byte) interfaceIdString.substring (24, 26).getHexValue32(), + (std::byte) interfaceIdString.substring (26, 28).getHexValue32(), + (std::byte) interfaceIdString.substring (28, 30).getHexValue32(), + (std::byte) interfaceIdString.substring (30, 32).getHexValue32() }; +} + +} // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h index 09c8cdb73a..cee4e6a305 100644 --- a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h @@ -104,16 +104,156 @@ struct VST3ClientExtensions */ virtual bool getPluginHasMainInput() const { return true; } - /** This function should return the UIDs of any compatible VST2 plug-ins. + using InterfaceId = std::array; - Each item in the vector should be a 32-character string consisting only - of the characters 0-9 and A-F. + /** This function should return the UIDs of any compatible VST2 or VST3 + plug-ins. This information will be used to implement the IPluginCompatibility interface. Hosts can use this interface to determine whether this VST3 is capable of replacing a given VST2. + + Each compatible class is a 16-byte array that corresponds to the VST3 + interface ID for the class implementing the IComponent interface. + For VST2 or JUCE plugins these IDs can be determined in the following + ways: + - Use convertVST2PluginId() for VST2 plugins or JUCE VST3 plugins with + JUCE_VST3_CAN_REPLACE_VST3 enabled + - Use convertJucePluginId() for any other JUCE VST3 plugins + + If JUCE_VST3_CAN_REPLACE_VST2 is enabled the VST3 plugin will have the + same identifier as the VST2 plugin and therefore there will be no need + to implement this function. + + If the parameter IDs between compatible versions differ + getCompatibleParameterIds() should also be overridden. However, unlike + getCompatibleParameterIds() this function should remain constant and + always return the same IDs. + + @see getCompatibleParameterIds() */ - virtual std::vector getCompatibleClasses() const { return {}; } + virtual std::vector getCompatibleClasses() const { return {}; } + + /** This function should return a map of VST3 parameter IDs and the JUCE + parameters they map to. + + This information is used to implement the IRemapParameter interface. + Hosts can use this to preserve automation data when a session was saved + using a compatible plugin that has different parameter IDs. + + Not all hosts will take this information into account. Therefore, + parameter IDs should be maintained between plugin versions. For JUCE + plugins migrating from VST2 to VST3 the best method for achieving this + is enabling JUCE_FORCE_LEGACY_PARAM_IDS. However, if a plugin has + already been released without enabling this flag, this method offers an + alternative approach that won't cause any further compatibility issues. + + The key in the map is a VST3 parameter identifier or Vst::ParamID. For + VST2 or JUCE plugins these IDs can be determined in the following ways + - Use the parameter index for + - VST2 plugins + - JUCE VST3 plugins with JUCE_FORCE_LEGACY_PARAM_IDS enabled + - Any parameter that doesn't inherit from HostedAudioProcessorParameter + - Use convertJuceParameterId() for JUCE VST3 plugins where + JUCE_FORCE_LEGACY_PARAM_IDS is disabled + + The value in the map is the JUCE parameter ID for the parameter to map + to, or an empty string to indicate that there is no parameter to map to. + If a parameter doesn't inherit from HostedAudioProcessorParameter its ID + will be the parameter index as a string, for example "1". Otherwise + always use the actual parameter ID (even if JUCE_FORCE_LEGACY_PARAM_IDS + is enabled). + + In the unlikely event that two plugins share the same plugin ID, and + both have a different parameters that share the same parameter ID, it + may be possible to determine which version of the plugin is being loaded + during setStateInformation(). This method will always be called after + setStateInformation(), so that the map with the correct mapping can be + provided when queried. + + Below is an example of how you might implement this function for a JUCE + VST3 plugin where JUCE_VST3_CAN_REPLACE_VST2 is enabled, but + JUCE_FORCE_LEGACY_PARAM_IDS is disabled. + + @code + std::map getCompatibleParameterIds (const String&) const override + { + return { { 0, "Frequency" }, + { 1, "CutOff" }, + { 2, "Gain" }, + { 3, "Bypass" } }; + } + @endcode + + @param compatibleClass A plugin identifier, either for the current + plugin or one listed in getCompatibleClasses(). + This parameter allows the implementation to + return a different parameter map for each + compatible class. Use convertJucePluginId() and + convertVST2PluginId() to determine the class IDs + used by JUCE plugins. + + @returns A map where each key is a VST3 parameter ID in the compatible + plugin, and the value is the unique JUCE parameter ID in the + current plugin that it should be mapped to. + + @see getCompatibleClasses, convertJucePluginId, convertVST2PluginId, convertJuceParameterId + */ + virtual std::map getCompatibleParameterIds (const InterfaceId& compatibleClass) const; + + /** An enum indicating the various VST3 interface types. + + In most cases users shouldn't need to concern themselves with any + interfaces other than the component, which is used to report the actual + audio effect. + */ + enum class InterfaceType + { + ara, + controller, + compatibility, + component, + processor + }; + + /** 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 convertVST2PluginId, getCompatibleClasses, getCompatibleParameterIds + */ + static InterfaceId convertJucePluginId (uint32_t manufacturerCode, + uint32_t pluginCode, + InterfaceType interfaceType = InterfaceType::component); + + /** Returns a 16-byte array indicating the VST3 interface ID used for a + given VST2 plugin. + + Internally JUCE will use this method to assign an ID for the component + and controller interfaces when JUCE_VST3_CAN_REPLACE_VST2 is enabled. + + @convertJucePluginId, getCompatibleClasses, getCompatibleParameterIds + */ + static InterfaceId convertVST2PluginId (uint32_t pluginCode, + const String& pluginName, + InterfaceType interfaceType = InterfaceType::component); + + /** Returns the VST3 compatible parameter ID reported for a given JUCE + parameter. + + Internally JUCE will use this method to determine the Vst::ParamID for + a HostedAudioProcessorParameter, unless JUCE_FORCE_LEGACY_PARAM_IDS is + enabled, in which case it will use the parameter index. + + @see getCompatibleParameterIds + */ + static uint32_t convertJuceParameterId (const String& parameterId, + bool studioOneCompatible = true); + + /** Converts a 32-character hex notation string to a VST3 interface ID. */ + static InterfaceId toInterfaceId (const String& interfaceIdString); }; } // namespace juce