From f3d7c74ea1ce9df539754dd3a5d09c4f8b40c1a1 Mon Sep 17 00:00:00 2001 From: Anthony Nicholls Date: Wed, 14 May 2025 10:27:35 +0100 Subject: [PATCH] VST3: Allow manifest helper to run independently --- BREAKING_CHANGES.md | 22 + CMakeLists.txt | 7 - .../Builds/Android/app/CMakeLists.txt | 6 +- .../VisualStudio2019/DemoRunner_App.vcxproj | 5 +- .../DemoRunner_App.vcxproj.filters | 21 +- .../VisualStudio2022/DemoRunner_App.vcxproj | 5 +- .../DemoRunner_App.vcxproj.filters | 21 +- .../Builds/Android/app/CMakeLists.txt | 6 +- .../AudioPerformanceTest_App.vcxproj | 5 +- .../AudioPerformanceTest_App.vcxproj.filters | 21 +- .../Builds/Android/app/CMakeLists.txt | 6 +- .../AudioPluginHost_App.vcxproj | 5 +- .../AudioPluginHost_App.vcxproj.filters | 21 +- .../AudioPluginHost_App.vcxproj | 5 +- .../AudioPluginHost_App.vcxproj.filters | 21 +- extras/Build/CMake/JUCEConfig.cmake.in | 1 - extras/Build/CMake/JUCEUtils.cmake | 45 +- .../Builds/Android/app/CMakeLists.txt | 6 +- .../NetworkGraphicsDemo_App.vcxproj | 5 +- .../NetworkGraphicsDemo_App.vcxproj.filters | 21 +- .../ProjectSaving/jucer_ProjectExport_MSVC.h | 9 +- .../ProjectSaving/jucer_ProjectExport_Make.h | 7 +- .../ProjectSaving/jucer_ProjectExport_Xcode.h | 33 +- .../UnitTestRunner_ConsoleApp.vcxproj | 5 +- .../UnitTestRunner_ConsoleApp.vcxproj.filters | 21 +- .../UnitTestRunner_ConsoleApp.vcxproj | 5 +- .../UnitTestRunner_ConsoleApp.vcxproj.filters | 21 +- .../WindowsDLL_DynamicLibrary.vcxproj | 5 +- .../WindowsDLL_DynamicLibrary.vcxproj.filters | 21 +- .../VST3/juce_VST3ManifestHelper.cpp | 139 +++++- .../VST3/juce_VST3ModuleInfo.h | 386 +++++++++++++++ .../juce_audio_plugin_client.h | 21 +- .../juce_audio_plugin_client_VST2.cpp | 6 +- .../juce_audio_plugin_client_VST3.cpp | 392 ++-------------- .../moduleinfotool/source/main.cpp | 441 ------------------ .../format_types/juce_VST3Common.h | 206 +------- .../format_types/juce_VST3Headers.h | 16 + .../format_types/juce_VST3PluginFormat.cpp | 12 +- .../juce_VST3PluginFormat_test.cpp | 1 + .../format_types/juce_VST3Utilities.h | 243 ++++++++++ .../juce_audio_processors.h | 1 + .../processors/juce_AudioProcessor.h | 4 +- .../utilities/ARA/juce_ARADebug.h | 4 +- .../utilities/juce_VST3ClientExtensions.cpp | 142 +----- .../utilities/juce_VST3ClientExtensions.h | 174 ++++--- .../utilities/juce_VST3Interface.h | 248 ++++++++++ 46 files changed, 1299 insertions(+), 1519 deletions(-) create mode 100644 modules/juce_audio_plugin_client/VST3/juce_VST3ModuleInfo.h delete mode 100644 modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp create mode 100644 modules/juce_audio_processors/format_types/juce_VST3Utilities.h create mode 100644 modules/juce_audio_processors/utilities/juce_VST3Interface.h diff --git a/BREAKING_CHANGES.md b/BREAKING_CHANGES.md index 630a59b114..240501dc49 100644 --- a/BREAKING_CHANGES.md +++ b/BREAKING_CHANGES.md @@ -1,5 +1,27 @@ # JUCE breaking changes +## Change + +Some functions and types have been moved from the VST3ClientExtentions class +into a new VST3Interface struct and JUCE_VST3_COMPATIBLE_CLASSES preprocessor +definition. + +**Possible Issues** + +Your project may not compile. + +**Workaround** + +Replace relevant types and function calls with the equivalent in the +VST3Interface struct, and/or define the JUCE_VST3_COMPATIBLE_CLASSES +preprocessor definition in your Projucer or CMake project. + +**Rationale** + +This change allows the VST3 helper executable to be built without needing to +depend on, and load, the plugin as part of the post build steps. + + # Version 8.0.7 ## Change diff --git a/CMakeLists.txt b/CMakeLists.txt index 34c98c82c9..fcb816e714 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -184,11 +184,4 @@ if(("${CMAKE_SOURCE_DIR}" STREQUAL "${JUCE_SOURCE_DIR}") AND (NOT JUCE_BUILD_HEL install(TARGETS juce_lv2_helper EXPORT LV2_HELPER DESTINATION "bin/JUCE-${JUCE_VERSION}") install(EXPORT LV2_HELPER NAMESPACE juce:: DESTINATION "${JUCE_INSTALL_DESTINATION}") endif() - - _juce_add_vst3_manifest_helper_target() - - if(TARGET juce_vst3_helper) - install(TARGETS juce_vst3_helper EXPORT VST3_HELPER DESTINATION "bin/JUCE-${JUCE_VERSION}") - install(EXPORT VST3_HELPER NAMESPACE juce:: DESTINATION "${JUCE_INSTALL_DESTINATION}") - endif() endif() diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt index edfb4f038f..13d7014a85 100644 --- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt +++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt @@ -725,7 +725,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -796,6 +795,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -862,6 +862,7 @@ add_library( ${BINARY_NAME} "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -3383,7 +3384,6 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -3454,6 +3454,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -3520,6 +3521,7 @@ set_source_files_properties( "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj index 9454ac3e34..7599772405 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj @@ -924,9 +924,6 @@ true - - true - true @@ -3731,6 +3728,7 @@ + @@ -3768,6 +3766,7 @@ + diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters index 877b8f35d3..24bb4fc7b8 100644 --- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters @@ -323,18 +323,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1633,9 +1621,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5499,6 +5484,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5610,6 +5598,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 eeb1fd8c0c..6d877a27d9 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj @@ -924,9 +924,6 @@ true - - true - true @@ -3731,6 +3728,7 @@ + @@ -3768,6 +3766,7 @@ + diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters index 16296c26c0..800afa748e 100644 --- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters +++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters @@ -323,18 +323,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1633,9 +1621,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5499,6 +5484,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5610,6 +5598,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 3c217456f0..2ccad172fb 100644 --- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt @@ -680,7 +680,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -751,6 +750,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -817,6 +817,7 @@ add_library( ${BINARY_NAME} "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -2952,7 +2953,6 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -3023,6 +3023,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -3089,6 +3090,7 @@ set_source_files_properties( "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj index 4077aad9a5..5dabc514ed 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj @@ -882,9 +882,6 @@ true - - true - true @@ -3245,6 +3242,7 @@ + @@ -3282,6 +3280,7 @@ + diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters index bace50fe0e..f5c2fa7388 100644 --- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters +++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters @@ -296,18 +296,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1414,9 +1402,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -4761,6 +4746,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -4872,6 +4860,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 801f1a47db..bf0710f7ba 100644 --- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt +++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt @@ -713,7 +713,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -784,6 +783,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -850,6 +850,7 @@ add_library( ${BINARY_NAME} "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -3138,7 +3139,6 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -3209,6 +3209,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -3275,6 +3276,7 @@ set_source_files_properties( "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj index 227b39cd9f..e947c78ba5 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj @@ -890,9 +890,6 @@ true - - true - true @@ -3425,6 +3422,7 @@ + @@ -3462,6 +3460,7 @@ + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters index 64440b3d61..5d8c24d5c7 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters @@ -305,18 +305,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1489,9 +1477,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5037,6 +5022,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5148,6 +5136,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 1627814fed..3c87281588 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj @@ -890,9 +890,6 @@ true - - true - true @@ -3425,6 +3422,7 @@ + @@ -3462,6 +3460,7 @@ + diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters index 57c4b9056c..181ee2f945 100644 --- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters +++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters @@ -305,18 +305,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1489,9 +1477,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5037,6 +5022,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5148,6 +5136,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/Build/CMake/JUCEConfig.cmake.in b/extras/Build/CMake/JUCEConfig.cmake.in index 03a09efb4a..14ae181644 100644 --- a/extras/Build/CMake/JUCEConfig.cmake.in +++ b/extras/Build/CMake/JUCEConfig.cmake.in @@ -21,7 +21,6 @@ @PACKAGE_INIT@ include("${CMAKE_CURRENT_LIST_DIR}/LV2_HELPER.cmake") -include("${CMAKE_CURRENT_LIST_DIR}/VST3_HELPER.cmake") if(NOT TARGET juce::juceaide) add_executable(juce::juceaide IMPORTED) diff --git a/extras/Build/CMake/JUCEUtils.cmake b/extras/Build/CMake/JUCEUtils.cmake index 308fe3e8ac..c03cfcdb94 100644 --- a/extras/Build/CMake/JUCEUtils.cmake +++ b/extras/Build/CMake/JUCEUtils.cmake @@ -1020,7 +1020,7 @@ endfunction() # ================================================================================================== -function(_juce_add_vst3_manifest_helper_target) +function(_juce_add_vst3_manifest_helper_target shared_code_target) if(TARGET juce_vst3_helper OR (CMAKE_SYSTEM_NAME STREQUAL "iOS") OR (CMAKE_SYSTEM_NAME STREQUAL "Android") @@ -1039,28 +1039,28 @@ function(_juce_add_vst3_manifest_helper_target) set(source "${module_path}/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.${extension}") - add_executable(juce_vst3_helper "${source}") - add_executable(juce::juce_vst3_helper ALIAS juce_vst3_helper) + set(vst3_helper_target ${shared_code_target}_vst3_helper) + add_executable(${vst3_helper_target} "${source}") + add_executable(juce::${vst3_helper_target} ALIAS ${vst3_helper_target}) - target_include_directories(juce_vst3_helper PRIVATE "${vst3_dir}" "${module_path}") + target_include_directories(${vst3_helper_target} PRIVATE "${vst3_dir}" "${module_path}") - add_library(juce_interface_definitions INTERFACE) - _juce_add_standard_defs(juce_interface_definitions) - target_link_libraries(juce_vst3_helper PRIVATE juce_interface_definitions) - target_compile_features(juce_vst3_helper PRIVATE cxx_std_17) + target_compile_definitions(${vst3_helper_target} PRIVATE + $>) - if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - _juce_link_frameworks(juce_vst3_helper PRIVATE Cocoa) - target_compile_options(juce_vst3_helper PRIVATE -fobjc-arc) - endif() + target_include_directories(${vst3_helper_target} PRIVATE + $>) - set_target_properties(juce_vst3_helper PROPERTIES BUILD_WITH_INSTALL_RPATH ON) - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - target_link_libraries(juce_vst3_helper PRIVATE Threads::Threads ${CMAKE_DL_LIBS} juce_recommended_config_flags) + target_compile_features(${vst3_helper_target} PRIVATE cxx_std_17) + + target_link_libraries(${vst3_helper_target} PRIVATE juce_recommended_config_flags) if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9) - target_link_libraries(juce_vst3_helper PRIVATE stdc++fs) + target_link_libraries(${vst3_helper_target} PRIVATE stdc++fs) + endif() + + if(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + _juce_link_frameworks(${vst3_helper_target} PRIVATE Foundation) endif() endfunction() @@ -1097,7 +1097,7 @@ function(juce_enable_vst3_manifest_step shared_code_target) endif() # Add a target for the helper tool - _juce_add_vst3_manifest_helper_target() + _juce_add_vst3_manifest_helper_target(${shared_code_target}) get_target_property(target_version_string ${shared_code_target} JUCE_VERSION) @@ -1105,14 +1105,9 @@ function(juce_enable_vst3_manifest_step shared_code_target) # Use the helper tool to write out the moduleinfo.json add_custom_command(TARGET ${target_name} POST_BUILD - COMMAND ${CMAKE_COMMAND} -E echo "creating ${ouput_path}" + COMMAND ${CMAKE_COMMAND} -E echo "creating ${output_path}" COMMAND ${CMAKE_COMMAND} -E make_directory "${product}/Contents/Resources" - COMMAND juce_vst3_helper - -create - -version "${target_version_string}" - -path "${product}" - -output "${ouput_path}" - VERBATIM) + COMMAND ${shared_code_target}_vst3_helper > "${ouput_path}") set_target_properties(${shared_code_target} PROPERTIES _JUCE_VST3_MANIFEST_STEP_ADDED TRUE) endfunction() diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt index b3502b4f3e..bb8244c728 100644 --- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt +++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt @@ -684,7 +684,6 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -755,6 +754,7 @@ add_library( ${BINARY_NAME} "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -821,6 +821,7 @@ add_library( ${BINARY_NAME} "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" @@ -3036,7 +3037,6 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/vst/vsttypes.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/LICENSE.txt" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/pluginterfaces/README.md" - "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.cpp" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/commonstringconvert.h" "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/common/memorystream.cpp" @@ -3107,6 +3107,7 @@ set_source_files_properties( "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat.h" "../../../../../modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp" + "../../../../../modules/juce_audio_processors/format_types/juce_VST3Utilities.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTCommon.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTMidiEventList.h" "../../../../../modules/juce_audio_processors/format_types/juce_VSTPluginFormat.cpp" @@ -3173,6 +3174,7 @@ set_source_files_properties( "../../../../../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/utilities/juce_VST3Interface.h" "../../../../../modules/juce_audio_processors/juce_audio_processors.cpp" "../../../../../modules/juce_audio_processors/juce_audio_processors.mm" "../../../../../modules/juce_audio_processors/juce_audio_processors_ara.cpp" diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj index 8593201874..4a95e18f40 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj @@ -882,9 +882,6 @@ true - - true - true @@ -3336,6 +3333,7 @@ + @@ -3373,6 +3371,7 @@ + diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters index a7ff5b74e5..8a16cb8319 100644 --- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters +++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters @@ -296,18 +296,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1444,9 +1432,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -4902,6 +4887,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5013,6 +5001,9 @@ JUCE Modules\juce_audio_processors\utilities + + JUCE Modules\juce_audio_processors\utilities + JUCE Modules\juce_audio_processors diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h index 6ade460502..d8f71b2335 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_MSVC.h @@ -1834,8 +1834,7 @@ public: + writerTarget->getBinaryNameWithSuffix (config); { - // moduleinfotool doesn't handle Windows-style path separators properly when computing the bundle name - const auto normalisedBundlePath = getOwner().getOutDirFile (config, segments[0]).replace ("\\", "/"); + const auto normalisedBundlePath = getOwner().getOutDirFile (config, segments[0]); const auto contentsDir = normalisedBundlePath + "\\Contents"; const auto resourceDir = contentsDir + "\\Resources"; const auto manifestPath = (resourceDir + "\\moduleinfo.json"); @@ -1845,10 +1844,8 @@ public: const auto manifestInvocationString = StringArray { helperExecutablePath.quoted(), - "-create", - "-version", getOwner().project.getVersionString().quoted(), - "-path", normalisedBundlePath.quoted(), - "-output", manifestPath.quoted() + ">", + manifestPath.quoted() }.joinIntoString (" "); const auto crossCompilationPairs = diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h index 2091036ab3..7344316f5f 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Make.h @@ -424,11 +424,8 @@ public: { out << "\t-$(V_AT)mkdir -p $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/Resources" << newLine << "\t-$(V_AT)rm -f $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/moduleinfo.json" << newLine - << "\t$(V_AT) $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER) " - "-create " - "-version " << owner.project.getVersionString().quoted() << " " - "-path $(JUCE_OUTDIR)/$(JUCE_VST3DIR) " - "-output $(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/Resources/moduleinfo.json" << newLine + << "\t$(V_AT) $(JUCE_OUTDIR)/$(JUCE_TARGET_VST3_MANIFEST_HELPER) > " + "$(JUCE_OUTDIR)/$(JUCE_VST3DIR)/Contents/Resources/moduleinfo.json" << newLine << "\t-$(V_AT)[ ! \"$(JUCE_VST3DESTDIR)\" ] || (mkdir -p $(JUCE_VST3DESTDIR) && cp -R $(JUCE_COPYCMD_VST3))" << newLine; } else if (type == VSTPlugIn) diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h index 2d19b77029..8a56311b04 100644 --- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h +++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExport_Xcode.h @@ -66,8 +66,13 @@ public: template ScriptBuilder& run (const String& command, Args&&... args) { - const auto joined = StringArray { command, std::forward (args)... }.joinIntoString (" "); - return echo ("Running " + joined).insertLine (joined); + const auto runCommand = StringArray { command, std::forward (args)... }.joinIntoString (" "); + const auto echoCommand = runCommand.replace ("|", "\\|") + .replace ("&", "\\&") + .replace ("<", "\\<") + .replace (">", "\\>"); + + return echo ("Running " + echoCommand).insertLine (runCommand); } ScriptBuilder& echo (const String& text) @@ -1439,9 +1444,7 @@ public: } if (type == XcodeTarget::LV2Helper || type == XcodeTarget::VST3Helper) - { return; - } if (type != XcodeTarget::SharedCodeTarget) // everything else depends on the sharedCodeTarget { @@ -2366,7 +2369,7 @@ private: if (target->type == XcodeTarget::LV2Helper) addFile (getFileOptions (getLV2HelperProgramSource())); else if (target->type == XcodeTarget::VST3Helper) - addFile (getFileOptions (getVST3HelperProgramSource()).withCompilerFlags ("-fobjc-arc")); + addFile (getFileOptions (getVST3HelperProgramSource())); } auto targetName = String (target->getName()); @@ -2546,17 +2549,18 @@ private: } } - // When building LV2 and VST3 plugins on Arm macs, we need to load and run the plugin - // bundle during a post-build step in order to generate the plugin's supporting files. - // Arm macs will only load shared libraries if they are signed, but Xcode runs its - // signing step after any post-build scripts. As a workaround, we sign the plugin - // using an adhoc certificate. if (target->type == XcodeTarget::VST3PlugIn || target->type == XcodeTarget::LV2PlugIn) { ScriptBuilder script; if (target->type == XcodeTarget::LV2PlugIn) { + // When building LV2 plugins on Arm macs, we need to load and run the plugin bundle + // during a post-build step in order to generate the plugin's supporting files. + // Arm macs will only load shared libraries if they are signed, but Xcode runs its + // signing step after any post-build scripts. As a workaround, we sign the plugin + // using an adhoc certificate. + // Note: LV2 has a non-standard config build dir script.run ("codesign --verbose=4 --force --sign -", doubleQuoted ("${CONFIGURATION_BUILD_DIR}/${EXECUTABLE_NAME}")) .insertLine() @@ -2565,13 +2569,8 @@ private: } else if (target->type == XcodeTarget::VST3PlugIn) { - script.run ("codesign --verbose=4 --force --sign -", doubleQuoted ("${CONFIGURATION_BUILD_DIR}/${WRAPPER_NAME}")) - .insertLine() - .run (doubleQuoted ("${CONFIGURATION_BUILD_DIR}/" + Project::getVST3FileWriterName()), - "-create", - "-version", doubleQuoted (project.getVersionString()), - "-path", doubleQuoted ("${CONFIGURATION_BUILD_DIR}/${WRAPPER_NAME}"), - "-output", doubleQuoted ("${CONFIGURATION_BUILD_DIR}/${WRAPPER_NAME}/Contents/Resources/moduleinfo.json")); + script.run (doubleQuoted ("${CONFIGURATION_BUILD_DIR}/" + Project::getVST3FileWriterName()), ">", + doubleQuoted ("${CONFIGURATION_BUILD_DIR}/${WRAPPER_NAME}/Contents/Resources/moduleinfo.json")); } target->addShellScriptBuildPhase ("Update manifest", script.toStringWithDefaultShellOptions()); diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj index 7e02304a8b..1f81c0163d 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj @@ -898,9 +898,6 @@ true - - true - true @@ -3537,6 +3534,7 @@ + @@ -3574,6 +3572,7 @@ + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters index 477d6c62f0..05bc025378 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -305,18 +305,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1537,9 +1525,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5196,6 +5181,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5307,6 +5295,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 2b5f6f0e36..f41b0d6e06 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj @@ -898,9 +898,6 @@ true - - true - true @@ -3537,6 +3534,7 @@ + @@ -3574,6 +3572,7 @@ + diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters index 5ad5888e06..580366010d 100644 --- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters +++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters @@ -305,18 +305,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1537,9 +1525,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -5196,6 +5181,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -5307,6 +5295,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 900210189b..9ad0c94d94 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj @@ -881,9 +881,6 @@ true - - true - true @@ -3312,6 +3309,7 @@ + @@ -3349,6 +3347,7 @@ + diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters index 0ad5e2b63e..9cb74f3ea3 100644 --- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters +++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_DynamicLibrary.vcxproj.filters @@ -290,18 +290,6 @@ {DAF30656-5915-0E45-C4E4-54439617D525} - - {600076D4-829D-CE7A-272C-832A4BBC40AB} - - - {C02D05C7-CD20-9901-2F02-95A9BD7FA797} - - - {47771136-6D29-90C7-2C6E-1728E7D1C485} - - - {3E938566-9812-78C0-9E81-75858F44C51F} - {9266EA90-6A0A-5DDB-9CB7-966BEF03BA5C} @@ -1441,9 +1429,6 @@ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\pluginterfaces\base - - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\samples\vst-utilities\moduleinfotool\source - JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\common @@ -4869,6 +4854,9 @@ JUCE Modules\juce_audio_processors\format_types + + JUCE Modules\juce_audio_processors\format_types + JUCE Modules\juce_audio_processors\format_types @@ -4980,6 +4968,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/VST3/juce_VST3ManifestHelper.cpp b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp index 7add601f14..4eea84017c 100644 --- a/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3ManifestHelper.cpp @@ -32,6 +32,28 @@ ============================================================================== */ +//============================================================================== +// This suppresses a warning caused by some of the Steinberg source code +#ifndef _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING + #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//============================================================================== // This suppresses a warning in juce_TargetPlatform.h #ifndef JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED #define JUCE_GLOBAL_MODULE_SETTINGS_INCLUDED 1 @@ -40,6 +62,7 @@ #include #include +//============================================================================== JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc++98-compat-extra-semi", "-Wdeprecated-declarations", "-Wexpansion-to-defined", @@ -56,36 +79,12 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wc++98-compat-extra-semi", JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387 6031) -// As of at least 3.7.12 there is a bug in fplatform.h that leads to SMTG_CPP20 -// having the wrong value when the /Zc:__cplusplus is not enabled. This work -// around prevents needing to provide that flag - -#include - -#ifdef SMTG_CPP20 - #undef SMTG_CPP20 - #define SMTG_CPP20 JUCE_CXX20_IS_AVAILABLE -#endif - -#ifndef _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING - #define _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING -#endif - #ifndef NOMINMAX - #define NOMINMAX 1 -#endif - -#if JUCE_MAC - #include -#elif JUCE_WINDOWS - #include -#elif JUCE_LINUX - #include + #define NOMINMAX #endif #include #include -#include #include #include #include @@ -97,3 +96,93 @@ JUCE_BEGIN_IGNORE_WARNINGS_MSVC (6387 6031) JUCE_END_IGNORE_WARNINGS_MSVC JUCE_END_IGNORE_WARNINGS_GCC_LIKE + +//============================================================================== +#if JucePlugin_Enable_ARA + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wpragma-pack") + #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE +#endif // JucePlugin_Enable_ARA + +//============================================================================== +#define jassert(x) assert ((x)) +#define jassertfalse assert (false) +#define DBG(x) +#define JUCE_DECLARE_NON_COPYABLE(x) +#define JUCE_API + +#if __has_include ("JucePluginDefines.h") + #include "JucePluginDefines.h" +#endif + +#include +#include +#include "juce_VST3ModuleInfo.h" + +//============================================================================== +class JucePluginModule : public VST3::Hosting::Module +{ +public: + JucePluginModule() + { + using namespace Steinberg; + using namespace VST3::Hosting; + PluginFactory tmp { owned (new juce::JucePluginFactoryBase()) }; + factory = std::move (tmp); + } + +private: + bool load (const std::string&, std::string&) final { return {}; } +}; + +std::optional loadCompatibilityFromModule (const VST3::Hosting::Module& pluginModule) +{ + const auto& factory = pluginModule.getFactory(); + const auto& infos = factory.classInfos(); + + const auto iter = std::find_if (infos.begin(), infos.end(), [&] (const auto& info) + { + return info.category() == kPluginCompatibilityClass; + }); + + if (iter == infos.end()) + return {}; + + const auto compatibility = factory.createInstance (iter->ID()); + + if (compatibility == nullptr) + return {}; + + Steinberg::MemoryStream stream; + + if (compatibility->getCompatibilityJSON (&stream) != Steinberg::kResultOk) + return {}; + + const std::string_view streamView (stream.getData(), stream.getSize()); + + return Steinberg::ModuleInfoLib::parseCompatibilityJson (streamView, nullptr); +} + +//============================================================================== +int main() +{ + const JucePluginModule pluginModule; + + auto moduleInfo = Steinberg::ModuleInfoLib::createModuleInfo (pluginModule, false); + + if (auto compatibility = loadCompatibilityFromModule (pluginModule)) + moduleInfo.compatibility = *compatibility; + + std::stringstream output; + Steinberg::ModuleInfoLib::outputJson (moduleInfo, output); + std::cout << output.str() << std::endl; + return 0; +} + +//============================================================================== +namespace VST3::Hosting +{ + Module::SnapshotList Module::getSnapshots (const std::string&) { return {}; } + Optional Module::getModuleInfoPath (const std::string&) { return {}; } + Module::Ptr Module::create (const std::string&, std::string&) { return {}; } +} // namespace VST3::Hosting diff --git a/modules/juce_audio_plugin_client/VST3/juce_VST3ModuleInfo.h b/modules/juce_audio_plugin_client/VST3/juce_VST3ModuleInfo.h new file mode 100644 index 0000000000..606b2930f5 --- /dev/null +++ b/modules/juce_audio_plugin_client/VST3/juce_VST3ModuleInfo.h @@ -0,0 +1,386 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#pragma once + +#ifndef DOXYGEN + +namespace juce +{ + +[[maybe_unused]] static Steinberg::FUID toSteinbergUID (const VST3Interface::Id& uid) +{ + return Steinberg::FUID::fromTUID ((const char*) (uid.data())); +} + +[[maybe_unused]] static VST3Interface::Id toVST3InterfaceId (const Steinberg::TUID uid) +{ + VST3Interface::Id iid; + std::memcpy (iid.data(), uid, iid.size()); + return iid; +} + +[[maybe_unused]] static VST3Interface::Id getVST3InterfaceId (VST3Interface::Type interfaceType) +{ + #if JUCE_VST3_CAN_REPLACE_VST2 + if (interfaceType == VST3Interface::Type::controller || interfaceType == VST3Interface::Type::component) + return VST3Interface::vst2PluginId (JucePlugin_VSTUniqueID, JucePlugin_Name, interfaceType); + #endif + + return VST3Interface::jucePluginId (JucePlugin_ManufacturerCode, JucePlugin_PluginCode, interfaceType); +} + +[[maybe_unused]] static std::vector getAllVST3CompatibleClasses() +{ + return + { + #if JUCE_VST3_CAN_REPLACE_VST2 + getVST3InterfaceId (VST3Interface::Type::component), + #endif + + #ifdef JUCE_VST3_COMPATIBLE_CLASSES + JUCE_VST3_COMPATIBLE_CLASSES + #endif + }; +} + +//============================================================================== +// See https://steinbergmedia.github.io/vst3_dev_portal/pages/FAQ/Compatibility+with+VST+2.x+or+VST+1.html + +#ifdef JUCE_VST3_COMPATIBLE_CLASSES +class JucePluginCompatibility final : public Steinberg::IPluginCompatibility +{ +public: + virtual ~JucePluginCompatibility() = default; + + JUCE_DECLARE_VST3_COM_REF_METHODS + + Steinberg::tresult PLUGIN_API getCompatibilityJSON (Steinberg::IBStream* stream) override + { + // We must avoid relying on any dependencies here including anything in juce_core + std::string json = std::invoke ([] + { + static const auto newId = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::component)); + static const auto oldIds = getAllVST3CompatibleClasses(); + + std::stringstream str; + str << "[{" + << "\"New\": \"" << VST3::UID { newId }.toString() << "\", " + << "\"Old\": ["; + + for (int i = 0; i < oldIds.size(); ++i) + { + str << "\"" + << std::hex + << std::setw (2) + << std::setfill ('0') + << std::uppercase; + + for (auto byte : oldIds[i]) + str << (int) byte; + + str.clear(); + str << "\""; + + if (i < oldIds.size() - 1) + str << ", "; + } + + str << "]}]"; + return str.str(); + }); + + return stream->write (json.data(), (Steinberg::int32) json.size()); + } + + Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID targetIID, + void** obj) override + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + jassertfalse; // Something new? + *obj = nullptr; + return Steinberg::kNotImplemented; + } + + inline static const Steinberg::FUID iid = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::compatibility)); + +private: + std::atomic refCount { 1 }; +}; +#endif // JUCE_VST3_COMPATIBLE_CLASSES + +//============================================================================== +class JucePluginFactoryBase : public Steinberg::IPluginFactory3 +{ +public: + JucePluginFactoryBase() = default; + virtual ~JucePluginFactoryBase() = default; + + //============================================================================== + JUCE_DECLARE_VST3_COM_REF_METHODS + + Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID targetIID, void** obj) final + { + const auto result = testForMultiple (*this, + targetIID, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}, + UniqueBase{}); + + if (result.isOk()) + return result.extract (obj); + + jassertfalse; // Something new? + *obj = nullptr; + return Steinberg::kNotImplemented; + } + + //============================================================================== + Steinberg::int32 PLUGIN_API countClasses() final + { + return (Steinberg::int32) getClassEntries().size; + } + + Steinberg::tresult PLUGIN_API getFactoryInfo (Steinberg::PFactoryInfo* info) final + { + if (info == nullptr) + return Steinberg::kInvalidArgument; + + std::memcpy (info, &factoryInfo, sizeof (factoryInfo)); + return Steinberg::kResultOk; + } + + Steinberg::tresult PLUGIN_API getClassInfo (Steinberg::int32 index, + Steinberg::PClassInfo* info) final + { + return getPClassInfo (index, info, &ClassEntry::info2); + } + + Steinberg::tresult PLUGIN_API getClassInfo2 (Steinberg::int32 index, + Steinberg::PClassInfo2* info) final + { + return getPClassInfo (index, info, &ClassEntry::info2); + } + + Steinberg::tresult PLUGIN_API getClassInfoUnicode (Steinberg::int32 index, + Steinberg::PClassInfoW* info) final + { + return getPClassInfo (index, info, &ClassEntry::infoW); + } + + Steinberg::tresult PLUGIN_API setHostContext (Steinberg::FUnknown*) override + { + jassertfalse; + return Steinberg::kNotImplemented; + } + + Steinberg::tresult PLUGIN_API createInstance (Steinberg::FIDString cid, + Steinberg::FIDString sourceIid, + void** obj) override + { + *obj = nullptr; + + Steinberg::TUID tuid; + std::memcpy (tuid, sourceIid, sizeof (tuid)); + + #if VST_VERSION >= 0x030608 + auto sourceFuid = Steinberg::FUID::fromTUID (tuid); + #else + FUID sourceFuid; + sourceFuid = tuid; + #endif + + if (cid == nullptr || sourceIid == nullptr || ! sourceFuid.isValid()) + { + jassertfalse; // The host you're running in has severe implementation issues! + return Steinberg::kInvalidArgument; + } + + Steinberg::TUID iidToQuery; + sourceFuid.toTUID (iidToQuery); + + for (auto& entry : getClassEntries()) + { + if (doUIDsMatch (entry.infoW.cid, cid)) + { + if (auto instance = becomeVSTComSmartPtrOwner (createInstance (entry))) + { + if (instance->queryInterface (iidToQuery, obj) == Steinberg::kResultOk) + return Steinberg::kResultOk; + } + + break; + } + } + + return Steinberg::kNoInterface; + } + +protected: + //============================================================================== + struct ClassEntry + { + #ifndef JucePlugin_Vst3ComponentFlags + #if JucePlugin_IsSynth + #define JucePlugin_Vst3ComponentFlags Steinberg::Vst::kSimpleModeSupported + #else + #define JucePlugin_Vst3ComponentFlags 0 + #endif + #endif + + #ifndef JucePlugin_Vst3Category + #if JucePlugin_IsSynth + #define JucePlugin_Vst3Category Steinberg::Vst::PlugType::kInstrumentSynth + #else + #define JucePlugin_Vst3Category Steinberg::Vst::PlugType::kFx + #endif + #endif + + ClassEntry (VST3Interface::Type interfaceType, + const char* name, + bool includeFlagsAndCategory) noexcept + : ClassEntry (getVST3InterfaceId (interfaceType), name, includeFlagsAndCategory) + {} + + ClassEntry (VST3Interface::Id interfaceId, + const char* name, + bool includeFlagsAndCategory) noexcept + : info2 ((const char*) interfaceId.data(), + Steinberg::PClassInfo::kManyInstances, + name, + JucePlugin_Name, + includeFlagsAndCategory ? JucePlugin_Vst3ComponentFlags : 0, + includeFlagsAndCategory ? JucePlugin_Vst3Category : "", + JucePlugin_Manufacturer, + JucePlugin_VersionString, + kVstVersionString) + { + infoW.fromAscii (info2); + } + + Steinberg::PClassInfo2 info2; + Steinberg::PClassInfoW infoW; + + private: + JUCE_DECLARE_NON_COPYABLE (ClassEntry) + }; + + struct ClassEntrySpan + { + const ClassEntry* data{}; + size_t size{}; + + const ClassEntry* begin() const { return data; } + const ClassEntry* end() const { return data + size; } + }; + + static ClassEntrySpan getClassEntries() + { + static const ClassEntry classEntries[] + { + #ifdef JUCE_VST3_COMPATIBLE_CLASSES + { VST3Interface::Type::compatibility, kPluginCompatibilityClass, false }, + #endif + { VST3Interface::Type::component, kVstAudioEffectClass, true }, + { VST3Interface::Type::controller, kVstComponentControllerClass, true }, + #if JucePlugin_Enable_ARA + { VST3Interface::Type::ara, kARAMainFactoryClass, true } + #endif + }; + + return { classEntries, std::size (classEntries) }; + } + + virtual Steinberg::FUnknown* createInstance (const ClassEntry& entry) + { + #ifdef JUCE_VST3_COMPATIBLE_CLASSES + if (doUIDsMatch (entry.info2.cid, JucePluginCompatibility::iid.toTUID())) + return new JucePluginCompatibility(); + #else + (void) entry; + #endif + + jassertfalse; + return {}; + } + +private: + const ClassEntry& getClassEntry (Steinberg::int32 index) const + { + return getClassEntries().data[index]; + } + + //============================================================================== + template + Steinberg::tresult PLUGIN_API getPClassInfo (Steinberg::int32 index, + PClassInfoTargetType* info, + PClassInfoSourceType ClassEntry::*source) + { + if (info == nullptr) + { + jassertfalse; + return Steinberg::kInvalidArgument; + } + + std::memcpy (info, &(getClassEntry (index).*source), sizeof (*info)); + return Steinberg::kResultOk; + } + + //============================================================================== + std::atomic refCount { 1 }; + const Steinberg::PFactoryInfo factoryInfo + { + JucePlugin_Manufacturer, + JucePlugin_ManufacturerWebsite, + JucePlugin_ManufacturerEmail, + Steinberg::Vst::kDefaultFactoryFlags + }; + + //============================================================================== + // no leak detector here to prevent it firing on shutdown when running in hosts that + // don't release the factory object correctly... + JUCE_DECLARE_NON_COPYABLE (JucePluginFactoryBase) +}; + +} // namespace juce + +#endif // DOXYGEN diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h index 8f775fcbfe..73b0e2165a 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client.h +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client.h @@ -68,12 +68,13 @@ Enable this if you want your VST3 plug-in to load and save VST2 compatible state. This allows hosts to replace VST2 plug-ins with VST3 plug-ins. If - you change this option then your VST3 plug-in will, by default, be incompatible - with previous versions. + you change this option then your VST3 plug-in will, by default, be + incompatible with previous versions. - If you've already released a VST2 and VST3 with this flag set to 0, you can still enable - migration from VST2 to VST3 on newer hosts. See VST3ClientExtensions::getCompatibleClasses() - and VST3ClientExtensions::getCompatibleParameterIds() for more details. + If you've already released a VST2 and VST3 with this flag set to 0, you can + still enable migration from VST2 to VST3 on newer hosts by defining the + JUCE_VST3_COMPATIBLE_CLASSES preprocessor and implementing the + VST3ClientExtensions::getCompatibleParameterIds() method. */ #ifndef JUCE_VST3_CAN_REPLACE_VST2 #define JUCE_VST3_CAN_REPLACE_VST2 1 @@ -81,10 +82,12 @@ /** Config: JUCE_FORCE_USE_LEGACY_PARAM_IDS - Enable this if you want to force JUCE to use a continuous parameter - index to identify a parameter in a DAW (this was the default in old - versions of JUCE). This is index is usually used by the DAW to save - automation data and enabling this may mess up user's DAW projects. + Enable this if you want to force JUCE to use a continuous parameter index to + identify a parameter in a DAW (this was the default in old versions of JUCE, + and is always the default for VST2 plugins). This index is usually used by + the DAW to save automation data. Changing this setting may mess up user's + DAW projects, see VST3ClientExtensions::getCompatibleParameterIds() for a + way to overcome this issue on newer VST3 hosts. */ #ifndef JUCE_FORCE_USE_LEGACY_PARAM_IDS #define JUCE_FORCE_USE_LEGACY_PARAM_IDS 0 diff --git a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp index 3bf0611131..c4058d9ec4 100644 --- a/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp +++ b/modules/juce_audio_plugin_client/juce_audio_plugin_client_VST2.cpp @@ -1814,9 +1814,9 @@ private: if (args.ptr == nullptr) return 0; - const auto uid = VST3ClientExtensions::convertVST2PluginId (JucePlugin_VSTUniqueID, - JucePlugin_Name, - VST3ClientExtensions::InterfaceType::component); + const auto uid = VST3Interface::vst2PluginId (JucePlugin_VSTUniqueID, + JucePlugin_Name, + VST3Interface::Type::component); std::copy (uid.begin(), uid.end(), reinterpret_cast (args.ptr)); return 1; #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 b9efb2d983..efb9c1589a 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 @@ -60,9 +60,12 @@ JUCE_BEGIN_NO_SANITIZE ("vptr") #include #include +//============================================================================== #include #include +#include #include +#include #if JUCE_VST3_CAN_REPLACE_VST2 && ! JUCE_FORCE_USE_LEGACY_PARAM_IDS && ! JUCE_IGNORE_VST3_MISMATCHED_PARAMETER_ID_WARNING @@ -111,51 +114,11 @@ JUCE_BEGIN_NO_SANITIZE ("vptr") #include #endif -//============================================================================== -#if JucePlugin_Enable_ARA - JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wpragma-pack") - #include - JUCE_END_IGNORE_WARNINGS_GCC_LIKE - - #if ARA_SUPPORT_VERSION_1 - #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation" - #endif - - DEF_CLASS_IID (ARA::IPlugInEntryPoint) - DEF_CLASS_IID (ARA::IPlugInEntryPoint2) - DEF_CLASS_IID (ARA::IMainFactory) -#endif - namespace juce { -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); @@ -623,7 +586,7 @@ public: bool isUsingManagedParameters() const noexcept { return juceParameters.isUsingManagedParameters(); } - std::map getParameterMap (const VST3InterfaceId& pluginId) const + std::map getParameterMap (const VST3Interface::Id& pluginId) const { const auto iter = compatibleParameterIdMap.find (pluginId); return iter != compatibleParameterIdMap.end() ? iter->second @@ -638,7 +601,7 @@ public: void updateParameterMapping() { - static const auto currentPluginId = getInterfaceId (VST3InterfaceType::component); + static const auto currentPluginId = getVST3InterfaceId (VST3Interface::Type::component); compatibleParameterIdMap = {}; compatibleParameterIdMap[currentPluginId] = paramMap; @@ -649,7 +612,7 @@ public: if (ext == nullptr) return; - for (const auto& compatibleClass : getAllCompatibleClasses (*audioProcessor)) + for (const auto& compatibleClass : getAllVST3CompatibleClasses()) { auto& parameterIdMap = compatibleParameterIdMap[compatibleClass]; for (auto [oldParamId, newParamId] : ext->getCompatibleParameterIds (compatibleClass)) @@ -678,28 +641,8 @@ public: } } - /* Includes all compatible classes declared in the client extensions, along with - our own ID in the case that JUCE_VST3_CAN_REPLACE_VST2 is set. - */ - static std::vector getAllCompatibleClasses (AudioProcessor& processor) - { - auto result = std::invoke ([&] - { - if (auto* ext = processor.getVST3ClientExtensions()) - return ext->getCompatibleClasses(); - - return std::vector{}; - }); - - #if JUCE_VST3_CAN_REPLACE_VST2 - result.push_back (getInterfaceId (VST3InterfaceType::component)); - #endif - - return result; - } - //============================================================================== - inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::processor)); + inline static const FUID iid = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::processor)); private: //============================================================================== @@ -810,7 +753,7 @@ private: CachedParamValues cachedParamValues; Vst::ParamID bypassParamID = 0, programParamID = static_cast (paramPreset); bool bypassIsRegularParameter = false; - std::map> compatibleParameterIdMap; + std::map> compatibleParameterIdMap; std::map juceIdParameterMap; //============================================================================== @@ -917,7 +860,7 @@ public: } //============================================================================== - inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::controller)); + inline static const FUID iid = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::controller)); //============================================================================== JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Winconsistent-missing-override") @@ -1273,7 +1216,7 @@ public: setParamNormalized (vstParamId, paramValue); } - if (! JuceAudioProcessor::getAllCompatibleClasses (*pluginInstance).empty()) + if (! getAllVST3CompatibleClasses().empty()) { restartFlags |= Vst::kParamIDMappingChanged; audioProcessor->updateParameterMapping(); @@ -2688,7 +2631,7 @@ private: return createARAFactory(); } - inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::ara)); + inline static const FUID iid = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::ara)); private: //============================================================================== @@ -2761,7 +2704,7 @@ public: AudioProcessor& getPluginInstance() const noexcept { return *pluginInstance; } //============================================================================== - inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::component)); + inline static const FUID iid = toSteinbergUID (getVST3InterfaceId (VST3Interface::Type::component)); JUCE_DECLARE_VST3_COM_REF_METHODS @@ -2985,7 +2928,7 @@ public: //============================================================================== bool shouldTryToLoadVst2State() { - return ! JuceAudioProcessor::getAllCompatibleClasses (*pluginInstance).empty(); + return ! getAllVST3CompatibleClasses().empty(); } bool shouldWriteStateWithVst2Compatibility() @@ -4138,182 +4081,21 @@ bool shutdownModule() } #endif -// See https://steinbergmedia.github.io/vst3_dev_portal/pages/FAQ/Compatibility+with+VST+2.x+or+VST+1.html -class JucePluginCompatibility final : public IPluginCompatibility +//============================================================================== +class JucePluginFactory final : public JucePluginFactoryBase { public: - virtual ~JucePluginCompatibility() = default; + JucePluginFactory() = default; - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API getCompatibilityJSON (IBStream* stream) override - { - const ScopedJuceInitialiser_GUI libraryInitialiser; - - auto filter = createPluginFilterOfType (AudioProcessor::WrapperType::wrapperType_VST3); - - const auto compatibilityObjects = std::invoke ([&] - { - const auto compatibleClasses = JuceAudioProcessor::getAllCompatibleClasses (*filter); - - if (compatibleClasses.empty()) - return Array(); - - DynamicObject::Ptr object { new DynamicObject }; - - // New iid is the ID of our Audio Effect class - object->setProperty ("New", String (VST3::UID (JuceVST3Component::iid).toString())); - object->setProperty ("Old", std::invoke ([&] - { - Array oldArray; - - for (const auto& uid : compatibleClasses) - oldArray.add (String::toHexString (uid.data(), (int) uid.size(), 0)); - - return oldArray; - })); - - return Array { object.get() }; - }); - - MemoryOutputStream memory; - JSON::writeToStream (memory, var { compatibilityObjects }); - return stream->write (memory.getMemoryBlock().getData(), (Steinberg::int32) memory.getDataSize()); - } - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}); - - if (result.isOk()) - return result.extract (obj); - - jassertfalse; // Something new? - *obj = nullptr; - return kNotImplemented; - } - - inline static const FUID iid = toSteinbergUID (getInterfaceId (VST3InterfaceType::compatibility)); - -private: - std::atomic refCount { 1 }; -}; - -//============================================================================== -using CreateFunction = FUnknown* (*) (const VSTComSmartPtr&, - const RunLoop&); - -//============================================================================== -struct JucePluginFactory final : public IPluginFactory3 -{ - JucePluginFactory() - : factoryInfo (JucePlugin_Manufacturer, JucePlugin_ManufacturerWebsite, - JucePlugin_ManufacturerEmail, Vst::kDefaultFactoryFlags) {} - - virtual ~JucePluginFactory() = default; - - //============================================================================== - JUCE_DECLARE_VST3_COM_REF_METHODS - - tresult PLUGIN_API queryInterface (const TUID targetIID, void** obj) override - { - const auto result = testForMultiple (*this, - targetIID, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}, - UniqueBase{}); - - if (result.isOk()) - return result.extract (obj); - - jassertfalse; // Something new? - *obj = nullptr; - return kNotImplemented; - } - - //============================================================================== - Steinberg::int32 PLUGIN_API countClasses() override - { - return (Steinberg::int32) getClassEntries().size(); - } - - tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) override - { - if (info == nullptr) - return kInvalidArgument; - - memcpy (info, &factoryInfo, sizeof (PFactoryInfo)); - return kResultOk; - } - - tresult PLUGIN_API getClassInfo (Steinberg::int32 index, PClassInfo* info) override - { - return getPClassInfo (index, info); - } - - tresult PLUGIN_API getClassInfo2 (Steinberg::int32 index, PClassInfo2* info) override - { - return getPClassInfo (index, info); - } - - tresult PLUGIN_API getClassInfoUnicode (Steinberg::int32 index, PClassInfoW* info) override - { - if (info != nullptr) - { - memcpy (info, &getClassEntries()[static_cast (index)].infoW, sizeof (PClassInfoW)); - return kResultOk; - } - - return kInvalidArgument; - } - - tresult PLUGIN_API createInstance (FIDString cid, FIDString sourceIid, void** obj) override + Steinberg::tresult PLUGIN_API createInstance (Steinberg::FIDString cid, + Steinberg::FIDString sourceIid, + void** obj) override { const ScopedRunLoop scope { runLoop }; - - *obj = nullptr; - - TUID tuid; - memcpy (tuid, sourceIid, sizeof (TUID)); - - #if VST_VERSION >= 0x030608 - auto sourceFuid = FUID::fromTUID (tuid); - #else - FUID sourceFuid; - sourceFuid = tuid; - #endif - - if (cid == nullptr || sourceIid == nullptr || ! sourceFuid.isValid()) - { - jassertfalse; // The host you're running in has severe implementation issues! - return kInvalidArgument; - } - - TUID iidToQuery; - sourceFuid.toTUID (iidToQuery); - - for (auto& entry : getClassEntries()) - { - if (doUIDsMatch (entry.infoW.cid, cid)) - { - if (auto instance = becomeVSTComSmartPtrOwner (entry.createFunction (host, runLoop))) - { - if (instance->queryInterface (iidToQuery, obj) == kResultOk) - return kResultOk; - } - - break; - } - } - - return kNoInterface; + return JucePluginFactoryBase::createInstance (cid, sourceIid, obj); } - tresult PLUGIN_API setHostContext (FUnknown* context) override + Steinberg::tresult PLUGIN_API setHostContext (Steinberg::FUnknown* context) override { runLoop.loadFrom (context); host.loadFrom (context); @@ -4330,136 +4112,24 @@ struct JucePluginFactory final : public IPluginFactory3 } private: - //============================================================================== - std::atomic refCount { 1 }; - const PFactoryInfo factoryInfo; - VSTComSmartPtr host; - RunLoop runLoop; - - //============================================================================== - struct ClassEntry + FUnknown* createInstance (const ClassEntry& entry) final { - ClassEntry (const PClassInfo2& info, CreateFunction fn) noexcept - : info2 (info), createFunction (fn) - { - infoW.fromAscii (info); - } + if (doUIDsMatch (entry.info2.cid, JuceVST3Component::iid)) + return static_cast (new JuceVST3Component (host, runLoop)); - PClassInfo2 info2; - PClassInfoW infoW; - CreateFunction createFunction = {}; + if (doUIDsMatch (entry.info2.cid, JuceVST3EditController::iid)) + return static_cast (new JuceVST3EditController (host, runLoop)); - private: - JUCE_DECLARE_NON_COPYABLE (ClassEntry) - }; - - static Span getClassEntries() - { - #ifndef JucePlugin_Vst3ComponentFlags - #if JucePlugin_IsSynth - #define JucePlugin_Vst3ComponentFlags Vst::kSimpleModeSupported - #else - #define JucePlugin_Vst3ComponentFlags 0 - #endif - #endif - - #ifndef JucePlugin_Vst3Category - #if JucePlugin_IsSynth - #define JucePlugin_Vst3Category Vst::PlugType::kInstrumentSynth - #else - #define JucePlugin_Vst3Category Vst::PlugType::kFx - #endif - #endif - - static const PClassInfo2 compatibilityClass { JucePluginCompatibility::iid, - PClassInfo::kManyInstances, - kPluginCompatibilityClass, - JucePlugin_Name, - 0, - "", - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString }; - - static const PClassInfo2 componentClass { JuceVST3Component::iid, - PClassInfo::kManyInstances, - kVstAudioEffectClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString }; - - static const PClassInfo2 controllerClass { JuceVST3EditController::iid, - PClassInfo::kManyInstances, - kVstComponentControllerClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString }; #if JucePlugin_Enable_ARA - static const PClassInfo2 araFactoryClass { JuceARAFactory::iid, - PClassInfo::kManyInstances, - kARAMainFactoryClass, - JucePlugin_Name, - JucePlugin_Vst3ComponentFlags, - JucePlugin_Vst3Category, - JucePlugin_Manufacturer, - JucePlugin_VersionString, - kVstVersionString }; + if (doUIDsMatch (entry.info2.cid, JuceARAFactory::iid)) + return static_cast (new JuceARAFactory()); #endif - static const ClassEntry classEntries[] - { - ClassEntry { componentClass, [] (const VSTComSmartPtr& h, - const RunLoop& l) -> FUnknown* - { - return static_cast (new JuceVST3Component (h, l)); - } }, - ClassEntry { controllerClass, [] (const VSTComSmartPtr& h, - const RunLoop& l) -> FUnknown* - { - return static_cast (new JuceVST3EditController (h, l)); - } }, - ClassEntry { compatibilityClass, [] (const VSTComSmartPtr&, - const RunLoop&) -> FUnknown* - { - return new JucePluginCompatibility; - } }, - #if JucePlugin_Enable_ARA - ClassEntry { araFactoryClass, [] (const VSTComSmartPtr&, - const RunLoop&) -> FUnknown* - { - return static_cast (new JuceARAFactory); - } }, - #endif - }; - - return Span { classEntries }; + return JucePluginFactoryBase::createInstance (entry); } - //============================================================================== - template - tresult PLUGIN_API getPClassInfo (Steinberg::int32 index, PClassInfoType* info) - { - if (info != nullptr) - { - zerostruct (*info); - memcpy (info, (PClassInfoType*) &getClassEntries()[static_cast (index)].info2, sizeof (PClassInfoType)); - return kResultOk; - } - - jassertfalse; - return kInvalidArgument; - } - - //============================================================================== - // no leak detector here to prevent it firing on shutdown when running in hosts that - // don't release the factory object correctly... - JUCE_DECLARE_NON_COPYABLE (JucePluginFactory) + RunLoop runLoop; + VSTComSmartPtr host; }; } // namespace juce diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp deleted file mode 100644 index a48e1eef01..0000000000 --- a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/samples/vst-utilities/moduleinfotool/source/main.cpp +++ /dev/null @@ -1,441 +0,0 @@ -//----------------------------------------------------------------------------- -// Project : VST SDK -// Flags : clang-format SMTGSequencer -// -// Category : moduleinfotool -// Filename : public.sdk/samples/vst-utilities/moduleinfotool/main.cpp -// Created by : Steinberg, 12/2021 -// Description : main entry point -// -//----------------------------------------------------------------------------- -// LICENSE -// (c) 2024, Steinberg Media Technologies GmbH, All Rights Reserved -//----------------------------------------------------------------------------- -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// * Neither the name of the Steinberg Media Technologies nor the names of its -// contributors may be used to endorse or promote products derived from this -// software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, -// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED -// OF THE POSSIBILITY OF SUCH DAMAGE. -//----------------------------------------------------------------------------- - -#include "pluginterfaces/base/iplugincompatibility.h" -#include "public.sdk/source/common/memorystream.h" - -#include "public.sdk/source/common/readfile.h" -#include "public.sdk/source/vst/hosting/module.h" -#include "public.sdk/source/vst/moduleinfo/moduleinfocreator.h" -#include "public.sdk/source/vst/moduleinfo/moduleinfoparser.h" -#include "public.sdk/source/vst/utility/stringconvert.h" -#include "base/source/fcommandline.h" -#include "pluginterfaces/base/fplatform.h" -#include "pluginterfaces/vst/vsttypes.h" -#include -#include -#include - -//------------------------------------------------------------------------ -namespace Steinberg { -namespace ModuleInfoTool { -namespace { - -//------------------------------------------------------------------------ -constexpr auto BUILD_INFO = "moduleinfotool 1.0.0 [Built " __DATE__ "]"; - -//------------------------------------------------------------------------ -//-- Options -constexpr auto optHelp = "help"; -constexpr auto optCreate = "create"; -constexpr auto optValidate = "validate"; -constexpr auto optModuleVersion = "version"; -constexpr auto optModulePath = "path"; -constexpr auto optInfoPath = "infopath"; -constexpr auto optModuleCompatPath = "compat"; -constexpr auto optOutputPath = "output"; - -//------------------------------------------------------------------------ -void printUsage (std::ostream& s) -{ - s << "Usage:\n"; - s << " moduleinfotool -create -version VERSION -path MODULE_PATH [-compat PATH -output PATH]\n"; - s << " moduleinfotool -validate -path MODULE_PATH [-infopath PATH]\n"; -} - -//------------------------------------------------------------------------ -std::optional openAndParseCompatJSON (const std::string& path) -{ - auto data = readFile (path); - if (data.empty ()) - { - std::cout << "Can not read '" << path << "'\n"; - printUsage (std::cout); - return {}; - } - std::stringstream error; - auto result = ModuleInfoLib::parseCompatibilityJson (data, &error); - if (!result) - { - std::cout << "Can not parse '" << path << "'\n"; - std::cout << error.str (); - printUsage (std::cout); - return {}; - } - return result; -} - -//------------------------------------------------------------------------ -std::optional loadCompatibilityFromModule (const VST3::Hosting::Module& module) -{ - const auto& factory = module.getFactory(); - const auto& infos = factory.classInfos(); - - const auto iter = std::find_if (infos.begin(), infos.end(), [&] (const auto& info) - { - return info.category() == kPluginCompatibilityClass; - }); - - if (iter == infos.end()) - return {}; - - const auto compatibility = factory.createInstance (iter->ID()); - - if (compatibility == nullptr) - return {}; - - Steinberg::MemoryStream stream; - - if (compatibility->getCompatibilityJSON (&stream) != kResultOk) - return {}; - - const std::string_view streamView (stream.getData(), stream.getSize()); - - return ModuleInfoLib::parseCompatibilityJson (streamView, nullptr); -} - -//------------------------------------------------------------------------ -int createJSON (const std::optional& compat, - const std::string& modulePath, const std::string& moduleVersion, - std::ostream& outStream) -{ - std::string errorStr; - auto module = VST3::Hosting::Module::create (modulePath, errorStr); - if (!module) - { - std::cout << errorStr; - return 1; - } - auto moduleInfo = ModuleInfoLib::createModuleInfo (*module, false); - if (compat) - moduleInfo.compatibility = *compat; - else if (auto loaded = loadCompatibilityFromModule (*module)) - moduleInfo.compatibility = *loaded; - - moduleInfo.version = moduleVersion; - - std::stringstream output; - ModuleInfoLib::outputJson (moduleInfo, output); - auto str = output.str (); - outStream << str; - return 0; -} - -//------------------------------------------------------------------------ -struct validate_error : std::exception -{ - validate_error (const std::string& str) : str (str) {} - const char* what () const noexcept override { return str.data (); } - -private: - std::string str; -}; - -//------------------------------------------------------------------------ -void validate (const ModuleInfo& moduleInfo, const VST3::Hosting::Module& module) -{ - auto factory = module.getFactory (); - auto factoryInfo = factory.info (); - auto classInfoList = factory.classInfos (); - auto snapshotList = module.getSnapshots (module.getPath ()); - - if (factoryInfo.vendor () != moduleInfo.factoryInfo.vendor) - throw validate_error ("factoryInfo.vendor different: " + moduleInfo.factoryInfo.vendor); - if (factoryInfo.url () != moduleInfo.factoryInfo.url) - throw validate_error ("factoryInfo.url different: " + moduleInfo.factoryInfo.url); - if (factoryInfo.email () != moduleInfo.factoryInfo.email) - throw validate_error ("factoryInfo.email different: " + moduleInfo.factoryInfo.email); - if (factoryInfo.flags () != moduleInfo.factoryInfo.flags) - throw validate_error ("factoryInfo.flags different: " + - std::to_string (moduleInfo.factoryInfo.flags)); - - for (const auto& ci : moduleInfo.classes) - { - auto cid = VST3::UID::fromString (ci.cid); - if (!cid) - throw validate_error ("could not parse class UID: " + ci.cid); - auto it = std::find_if (classInfoList.begin (), classInfoList.end (), - [&] (const auto& el) { return el.ID () == *cid; }); - if (it == classInfoList.end ()) - throw validate_error ("cannot find CID in class list: " + ci.cid); - if (it->name () != ci.name) - throw validate_error ("class name different: " + ci.name); - if (it->category () != ci.category) - throw validate_error ("class category different: " + ci.category); - if (it->vendor () != ci.vendor) - throw validate_error ("class vendor different: " + ci.vendor); - if (it->version () != ci.version) - throw validate_error ("class version different: " + ci.version); - if (it->sdkVersion () != ci.sdkVersion) - throw validate_error ("class sdkVersion different: " + ci.sdkVersion); - if (it->subCategories () != ci.subCategories) - throw validate_error ("class subCategories different: " /* + ci.subCategories*/); - if (it->cardinality () != ci.cardinality) - throw validate_error ("class cardinality different: " + - std::to_string (ci.cardinality)); - if (it->classFlags () != ci.flags) - throw validate_error ("class flags different: " + std::to_string (ci.flags)); - classInfoList.erase (it); - - auto snapshotListIt = std::find_if (snapshotList.begin (), snapshotList.end (), - [&] (const auto& el) { return el.uid == *cid; }); - if (snapshotListIt == snapshotList.end () && !ci.snapshots.empty ()) - throw validate_error ("cannot find snapshots for: " + ci.cid); - for (const auto& snapshot : ci.snapshots) - { - auto snapshotIt = std::find_if ( - snapshotListIt->images.begin (), snapshotListIt->images.end (), - [&] (const auto& el) { return el.scaleFactor == snapshot.scaleFactor; }); - if (snapshotIt == snapshotListIt->images.end ()) - throw validate_error ("cannot find snapshots for scale factor: " + - std::to_string (snapshot.scaleFactor)); - std::string_view path (snapshotIt->path); - if (path.find (module.getPath ()) == 0) - path.remove_prefix (module.getPath ().size () + 1); - if (path != snapshot.path) - throw validate_error ("cannot find snapshots with path: " + snapshot.path); - snapshotListIt->images.erase (snapshotIt); - } - if (snapshotListIt != snapshotList.end () && !snapshotListIt->images.empty ()) - { - std::string errorStr = "Missing Snapshots in moduleinfo:\n"; - for (const auto& s : snapshotListIt->images) - { - errorStr += s.path + '\n'; - } - throw validate_error (errorStr); - } - if (snapshotListIt != snapshotList.end ()) - snapshotList.erase (snapshotListIt); - } - if (!classInfoList.empty ()) - throw validate_error ("Missing classes in moduleinfo"); - if (!snapshotList.empty ()) - throw validate_error ("Missing snapshots in moduleinfo"); -} - -//------------------------------------------------------------------------ -int validate (const std::string& modulePath, std::string infoJsonPath) -{ - if (infoJsonPath.empty ()) - { - auto path = VST3::Hosting::Module::getModuleInfoPath (modulePath); - if (!path) - { - std::cerr << "Module does not contain a moduleinfo.json: '" << modulePath << "'" - << '\n'; - return 1; - } - infoJsonPath = *path; - } - - auto data = readFile (infoJsonPath); - if (data.empty ()) - { - std::cerr << "Empty or non existing file: '" << infoJsonPath << "'" << '\n'; - printUsage (std::cout); - return 1; - } - auto moduleInfo = ModuleInfoLib::parseJson (data, &std::cerr); - if (moduleInfo) - { - std::string errorStr; - auto module = VST3::Hosting::Module::create (modulePath, errorStr); - if (!module) - { - std::cerr << errorStr; - printUsage (std::cout); - return 1; - } - try - { - validate (*moduleInfo, *module); - } - catch (const std::exception& exc) - { - std::cerr << "Error:\n" << exc.what () << '\n'; - printUsage (std::cout); - return 1; - } - return 0; - } - printUsage (std::cout); - return 1; -} - -//------------------------------------------------------------------------ -} // anonymous - -//------------------------------------------------------------------------ -int run (int argc, char* argv[]) -{ - // parse command line - CommandLine::Descriptions desc; - CommandLine::VariablesMap valueMap; - CommandLine::FilesVector files; - - using Description = CommandLine::Description; - desc.addOptions ( - BUILD_INFO, - { - {optCreate, "Create moduleinfo", Description::kBool}, - {optValidate, "Validate moduleinfo", Description::kBool}, - {optModuleVersion, "Module version", Description::kString}, - {optModulePath, "Path to module", Description::kString}, - {optInfoPath, "Path to moduleinfo.json", Description::kString}, - {optModuleCompatPath, "Path to compatibility.json", Description::kString}, - {optOutputPath, "Write json to file instead of stdout", Description::kString}, - {optHelp, "Print help", Description::kBool}, - }); - CommandLine::parse (argc, argv, desc, valueMap, &files); - - bool isCreate = valueMap.count (optCreate) != 0 && valueMap.count (optModuleVersion) != 0 && - valueMap.count (optModulePath) != 0; - bool isValidate = valueMap.count (optValidate) && valueMap.count (optModulePath) != 0; - - if (valueMap.hasError () || valueMap.count (optHelp) || !(isCreate || isValidate)) - { - std::cout << '\n' << desc << '\n'; - printUsage (std::cout); - return 1; - } - - int result = 1; - - const auto& modulePath = valueMap[optModulePath]; - if (isCreate) - { - auto* outputStream = &std::cout; - std::optional compat; - if (valueMap.count (optModuleCompatPath) != 0) - { - const auto& compatPath = valueMap[optModuleCompatPath]; - compat = openAndParseCompatJSON (compatPath); - if (!compat) - return 1; - } - bool writeToFile = false; - if (valueMap.count (optOutputPath) != 0) - { - writeToFile = true; -#if SMTG_OS_WINDOWS - auto tmp = Vst::StringConvert::convert (valueMap[optOutputPath]); - auto outputFile = reinterpret_cast (tmp.data ()); -#else - auto outputFile = valueMap[optOutputPath]; -#endif - auto ostream = new std::ofstream (outputFile); - - if (ostream->is_open ()) - outputStream = ostream; - else - { - std::cout << "Cannot create output file: " << valueMap[optOutputPath] << '\n'; - return result; - } - } - const auto& moduleVersion = valueMap[optModuleVersion]; - result = createJSON (compat, modulePath, moduleVersion, *outputStream); - if (writeToFile) - delete outputStream; - } - else if (isValidate) - { - std::string moduleInfoJsonPath; - if (valueMap.count (optInfoPath) != 0) - moduleInfoJsonPath = valueMap[optInfoPath]; - result = validate (modulePath, moduleInfoJsonPath); - } - return result; -} - -//------------------------------------------------------------------------ -} // ModuleInfoTool -} // Steinberg - -//------------------------------------------------------------------------ -#if SMTG_OS_WINDOWS -//------------------------------------------------------------------------ -using Utf8String = std::string; - -//------------------------------------------------------------------------ -using Utf8Args = std::vector; -Utf8Args toUtf8Args (int argc, wchar_t* wargv[]) -{ - Utf8Args utf8Args; - for (int i = 0; i < argc; i++) - { - auto str = reinterpret_cast (wargv[i]); - utf8Args.push_back (Steinberg::Vst::StringConvert::convert (str)); - } - - return utf8Args; -} - -//------------------------------------------------------------------------ -using Utf8ArgPtrs = std::vector; -Utf8ArgPtrs toUtf8ArgPtrs (Utf8Args& utf8Args) -{ - Utf8ArgPtrs utf8ArgPtrs; - for (auto& el : utf8Args) - { - utf8ArgPtrs.push_back (el.data ()); - } - - return utf8ArgPtrs; -} - -//------------------------------------------------------------------------ -int wmain (int argc, wchar_t* wargv[]) -{ - Utf8Args utf8Args = toUtf8Args (argc, wargv); - Utf8ArgPtrs utf8ArgPtrs = toUtf8ArgPtrs (utf8Args); - - char** argv = &(utf8ArgPtrs.at (0)); - return Steinberg::ModuleInfoTool::run (argc, argv); -} - -#else - -//------------------------------------------------------------------------ -int main (int argc, char* argv[]) -{ - return Steinberg::ModuleInfoTool::run (argc, argv); -} - -//------------------------------------------------------------------------ -#endif // SMTG_OS_WINDOWS diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 6b93925de9..107f61321f 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -41,129 +41,6 @@ namespace juce JUCE_BEGIN_NO_SANITIZE ("vptr") -//============================================================================== -#define JUCE_DECLARE_VST3_COM_REF_METHODS \ - Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \ - Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; } - -#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \ - Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \ - { \ - jassertfalse; \ - *obj = nullptr; \ - return Steinberg::kNotImplemented; \ - } - -inline bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept -{ - return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0; -} - -/* Holds a tresult and a pointer to an object. - - Useful for holding intermediate results of calls to queryInterface. -*/ -class QueryInterfaceResult -{ -public: - QueryInterfaceResult() = default; - - QueryInterfaceResult (Steinberg::tresult resultIn, void* ptrIn) - : result (resultIn), ptr (ptrIn) {} - - bool isOk() const noexcept { return result == Steinberg::kResultOk; } - - Steinberg::tresult extract (void** obj) const - { - *obj = result == Steinberg::kResultOk ? ptr : nullptr; - return result; - } - -private: - Steinberg::tresult result = Steinberg::kResultFalse; - void* ptr = nullptr; -}; - -/* Holds a tresult and a pointer to an object. - - Calling InterfaceResultWithDeferredAddRef::extract() will also call addRef - on the pointed-to object. It is expected that users will use - InterfaceResultWithDeferredAddRef to hold intermediate results of a queryInterface - call. When a suitable interface is found, the function can be exited with - `return suitableInterface.extract (obj)`, which will set the obj pointer, - add a reference to the interface, and return the appropriate result code. -*/ -class InterfaceResultWithDeferredAddRef -{ -public: - InterfaceResultWithDeferredAddRef() = default; - - template - InterfaceResultWithDeferredAddRef (Steinberg::tresult resultIn, Ptr* ptrIn) - : result (resultIn, ptrIn), - addRefFn (doAddRef) {} - - bool isOk() const noexcept { return result.isOk(); } - - Steinberg::tresult extract (void** obj) const - { - const auto toReturn = result.extract (obj); - - if (result.isOk() && *obj != nullptr) - NullCheckedInvocation::invoke (addRefFn, *obj); - - return toReturn; - } - -private: - template - static void doAddRef (void* obj) { static_cast (obj)->addRef(); } - - QueryInterfaceResult result; - void (*addRefFn) (void*) = nullptr; -}; - -template struct UniqueBase {}; -template struct SharedBase {}; - -template -InterfaceResultWithDeferredAddRef testFor (ToTest& toTest, - const Steinberg::TUID targetIID, - SharedBase) -{ - if (! doUIDsMatch (targetIID, CommonClassType::iid)) - return {}; - - return { Steinberg::kResultOk, static_cast (static_cast (std::addressof (toTest))) }; -} - -template -InterfaceResultWithDeferredAddRef testFor (ToTest& toTest, - const Steinberg::TUID targetIID, - UniqueBase) -{ - return testFor (toTest, targetIID, SharedBase{}); -} - -template -InterfaceResultWithDeferredAddRef testForMultiple (ToTest&, const Steinberg::TUID) { return {}; } - -template -InterfaceResultWithDeferredAddRef testForMultiple (ToTest& toTest, const Steinberg::TUID targetIID, Head head, Tail... tail) -{ - const auto result = testFor (toTest, targetIID, head); - - if (result.isOk()) - return result; - - return testForMultiple (toTest, targetIID, tail...); -} - -//============================================================================== -#if VST_VERSION < 0x030608 - #define kAmbi1stOrderACN kBFormat -#endif - //============================================================================== inline juce::String toString (const Steinberg::char8* string) noexcept { return juce::String (juce::CharPointer_UTF8 ((juce::CharPointer_UTF8::CharType*) string)); } inline juce::String toString (const Steinberg::char16* string) noexcept { return juce::String (juce::CharPointer_UTF16 ((juce::CharPointer_UTF16::CharType*) string)); } @@ -184,6 +61,11 @@ inline void toString128 (Steinberg::Vst::String128 result, const juce::String& s Steinberg::UString (result, 128).assign (toString (source)); } +//============================================================================== +#if VST_VERSION < 0x030608 + #define kAmbi1stOrderACN kBFormat +#endif + #if JUCE_WINDOWS static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeHWND; #elif JUCE_MAC @@ -192,7 +74,6 @@ inline void toString128 (Steinberg::Vst::String128 result, const juce::String& s static const Steinberg::FIDString defaultVST3WindowType = Steinberg::kPlatformTypeX11EmbedWindowID; #endif - //============================================================================== static inline Steinberg::Vst::SpeakerArrangement getArrangementForBus (Steinberg::Vst::IAudioProcessor* processor, bool isInput, int busIndex) @@ -1192,83 +1073,6 @@ private: std::vector mappings; }; -//============================================================================== -// We have to trust that Steinberg won't double-delete -// NOLINTBEGIN(clang-analyzer-cplusplus.NewDelete) -template -class VSTComSmartPtr -{ -public: - VSTComSmartPtr() = default; - VSTComSmartPtr (const VSTComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); } - ~VSTComSmartPtr() { if (source != nullptr) source->release(); } - - explicit operator bool() const noexcept { return operator!= (nullptr); } - ObjectType* get() const noexcept { return source; } - ObjectType& operator*() const noexcept { return *source; } - ObjectType* operator->() const noexcept { return source; } - - VSTComSmartPtr& operator= (const VSTComSmartPtr& other) - { - auto p = other; - std::swap (p.source, source); - return *this; - } - - VSTComSmartPtr& operator= (std::nullptr_t) - { - return operator= (VSTComSmartPtr{}); - } - - bool operator== (std::nullptr_t) const noexcept { return source == nullptr; } - bool operator!= (std::nullptr_t) const noexcept { return source != nullptr; } - - bool loadFrom (Steinberg::FUnknown* o) - { - *this = nullptr; - return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk; - } - - bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid) - { - jassert (factory != nullptr); - *this = nullptr; - return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk; - } - - /** Increments refcount. */ - static auto addOwner (ObjectType* t) - { - return VSTComSmartPtr (t, true); - } - - /** Does not initially increment refcount; assumes t has a positive refcount. */ - static auto becomeOwner (ObjectType* t) - { - return VSTComSmartPtr (t, false); - } - -private: - explicit VSTComSmartPtr (ObjectType* object, bool autoAddRef) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); } - ObjectType* source = nullptr; -}; - -/** Increments refcount. */ -template -auto addVSTComSmartPtrOwner (ObjectType* t) -{ - return VSTComSmartPtr::addOwner (t); -} - -/** Does not initially increment refcount; assumes t has a positive refcount. */ -template -auto becomeVSTComSmartPtrOwner (ObjectType* t) -{ - return VSTComSmartPtr::becomeOwner (t); -} - -// NOLINTEND(clang-analyzer-cplusplus.NewDelete) - //============================================================================== /* This class stores a plugin's preferred MIDI mappings. diff --git a/modules/juce_audio_processors/format_types/juce_VST3Headers.h b/modules/juce_audio_processors/format_types/juce_VST3Headers.h index 37f38d5779..2ad8272a28 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Headers.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Headers.h @@ -245,6 +245,22 @@ namespace Presonus JUCE_END_IGNORE_WARNINGS_MSVC JUCE_END_IGNORE_WARNINGS_GCC_LIKE +//============================================================================== +#if JucePlugin_Enable_ARA + JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wpragma-pack") + #include + JUCE_END_IGNORE_WARNINGS_GCC_LIKE + + #if ARA_SUPPORT_VERSION_1 + #error "Unsupported ARA version - only ARA version 2 and onward are supported by the current implementation" + #endif + + DEF_CLASS_IID (ARA::IPlugInEntryPoint) + DEF_CLASS_IID (ARA::IPlugInEntryPoint2) + DEF_CLASS_IID (ARA::IMainFactory) +#endif // JucePlugin_Enable_ARA + +//============================================================================== #if JUCE_WINDOWS #include #endif diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp index 82a9e601be..8cba7db9fe 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat.cpp @@ -35,20 +35,10 @@ #if JUCE_PLUGINHOST_VST3 && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD) #include "juce_VST3Headers.h" +#include "juce_VST3Utilities.h" #include "juce_VST3Common.h" #include "juce_ARACommon.h" -#if JUCE_PLUGINHOST_ARA && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) -#include - -namespace ARA -{ -DEF_CLASS_IID (IMainFactory) -DEF_CLASS_IID (IPlugInEntryPoint) -DEF_CLASS_IID (IPlugInEntryPoint2) -} -#endif - namespace juce { diff --git a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp index ff6841a9b5..a1954b1c6b 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp +++ b/modules/juce_audio_processors/format_types/juce_VST3PluginFormat_test.cpp @@ -33,6 +33,7 @@ */ #include "juce_VST3Headers.h" +#include "juce_VST3Utilities.h" #include "juce_VST3Common.h" namespace juce diff --git a/modules/juce_audio_processors/format_types/juce_VST3Utilities.h b/modules/juce_audio_processors/format_types/juce_VST3Utilities.h new file mode 100644 index 0000000000..a8782c570c --- /dev/null +++ b/modules/juce_audio_processors/format_types/juce_VST3Utilities.h @@ -0,0 +1,243 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#pragma once + +#ifndef DOXYGEN + +namespace juce +{ + +JUCE_BEGIN_NO_SANITIZE ("vptr") + +//============================================================================== +#define JUCE_DECLARE_VST3_COM_REF_METHODS \ + Steinberg::uint32 PLUGIN_API addRef() override { return (Steinberg::uint32) ++refCount; } \ + Steinberg::uint32 PLUGIN_API release() override { const int r = --refCount; if (r == 0) delete this; return (Steinberg::uint32) r; } + +#define JUCE_DECLARE_VST3_COM_QUERY_METHODS \ + Steinberg::tresult PLUGIN_API queryInterface (const Steinberg::TUID, void** obj) override \ + { \ + jassertfalse; \ + *obj = nullptr; \ + return Steinberg::kNotImplemented; \ + } + +inline bool doUIDsMatch (const Steinberg::TUID a, const Steinberg::TUID b) noexcept +{ + return std::memcmp (a, b, sizeof (Steinberg::TUID)) == 0; +} + +/* Holds a tresult and a pointer to an object. + + Useful for holding intermediate results of calls to queryInterface. +*/ +class QueryInterfaceResult +{ +public: + QueryInterfaceResult() = default; + + QueryInterfaceResult (Steinberg::tresult resultIn, void* ptrIn) + : result (resultIn), ptr (ptrIn) {} + + bool isOk() const noexcept { return result == Steinberg::kResultOk; } + + Steinberg::tresult extract (void** obj) const + { + *obj = result == Steinberg::kResultOk ? ptr : nullptr; + return result; + } + +private: + Steinberg::tresult result = Steinberg::kResultFalse; + void* ptr = nullptr; +}; + +/* Holds a tresult and a pointer to an object. + + Calling InterfaceResultWithDeferredAddRef::extract() will also call addRef + on the pointed-to object. It is expected that users will use + InterfaceResultWithDeferredAddRef to hold intermediate results of a queryInterface + call. When a suitable interface is found, the function can be exited with + `return suitableInterface.extract (obj)`, which will set the obj pointer, + add a reference to the interface, and return the appropriate result code. +*/ +class InterfaceResultWithDeferredAddRef +{ +public: + InterfaceResultWithDeferredAddRef() = default; + + template + InterfaceResultWithDeferredAddRef (Steinberg::tresult resultIn, Ptr* ptrIn) + : result (resultIn, ptrIn), + addRefFn (doAddRef) {} + + bool isOk() const noexcept { return result.isOk(); } + + Steinberg::tresult extract (void** obj) const + { + const auto toReturn = result.extract (obj); + + if (result.isOk() && *obj != nullptr && addRefFn != nullptr) + addRefFn (*obj); + + return toReturn; + } + +private: + template + static void doAddRef (void* obj) { static_cast (obj)->addRef(); } + + QueryInterfaceResult result; + void (*addRefFn) (void*) = nullptr; +}; + +template struct UniqueBase {}; +template struct SharedBase {}; + +template +InterfaceResultWithDeferredAddRef testFor (ToTest& toTest, + const Steinberg::TUID targetIID, + SharedBase) +{ + if (! doUIDsMatch (targetIID, CommonClassType::iid)) + return {}; + + return { Steinberg::kResultOk, static_cast (static_cast (std::addressof (toTest))) }; +} + +template +InterfaceResultWithDeferredAddRef testFor (ToTest& toTest, + const Steinberg::TUID targetIID, + UniqueBase) +{ + return testFor (toTest, targetIID, SharedBase{}); +} + +template +InterfaceResultWithDeferredAddRef testForMultiple (ToTest&, const Steinberg::TUID) { return {}; } + +template +InterfaceResultWithDeferredAddRef testForMultiple (ToTest& toTest, const Steinberg::TUID targetIID, Head head, Tail... tail) +{ + const auto result = testFor (toTest, targetIID, head); + + if (result.isOk()) + return result; + + return testForMultiple (toTest, targetIID, tail...); +} + +//============================================================================== +// We have to trust that Steinberg won't double-delete +// NOLINTBEGIN(clang-analyzer-cplusplus.NewDelete) +template +class VSTComSmartPtr +{ +public: + VSTComSmartPtr() = default; + VSTComSmartPtr (const VSTComSmartPtr& other) noexcept : source (other.source) { if (source != nullptr) source->addRef(); } + ~VSTComSmartPtr() { if (source != nullptr) source->release(); } + + explicit operator bool() const noexcept { return operator!= (nullptr); } + ObjectType* get() const noexcept { return source; } + ObjectType& operator*() const noexcept { return *source; } + ObjectType* operator->() const noexcept { return source; } + + VSTComSmartPtr& operator= (const VSTComSmartPtr& other) + { + auto p = other; + std::swap (p.source, source); + return *this; + } + + VSTComSmartPtr& operator= (std::nullptr_t) + { + return operator= (VSTComSmartPtr{}); + } + + bool operator== (std::nullptr_t) const noexcept { return source == nullptr; } + bool operator!= (std::nullptr_t) const noexcept { return source != nullptr; } + + bool loadFrom (Steinberg::FUnknown* o) + { + *this = nullptr; + return o != nullptr && o->queryInterface (ObjectType::iid, (void**) &source) == Steinberg::kResultOk; + } + + bool loadFrom (Steinberg::IPluginFactory* factory, const Steinberg::TUID& uuid) + { + jassert (factory != nullptr); + *this = nullptr; + return factory->createInstance (uuid, ObjectType::iid, (void**) &source) == Steinberg::kResultOk; + } + + /** Increments refcount. */ + static auto addOwner (ObjectType* t) + { + return VSTComSmartPtr (t, true); + } + + /** Does not initially increment refcount; assumes t has a positive refcount. */ + static auto becomeOwner (ObjectType* t) + { + return VSTComSmartPtr (t, false); + } + +private: + explicit VSTComSmartPtr (ObjectType* object, bool autoAddRef) noexcept : source (object) { if (source != nullptr && autoAddRef) source->addRef(); } + ObjectType* source = nullptr; +}; + +/** Increments refcount. */ +template +auto addVSTComSmartPtrOwner (ObjectType* t) +{ + return VSTComSmartPtr::addOwner (t); +} + +/** Does not initially increment refcount; assumes t has a positive refcount. */ +template +auto becomeVSTComSmartPtrOwner (ObjectType* t) +{ + return VSTComSmartPtr::becomeOwner (t); +} + +// NOLINTEND(clang-analyzer-cplusplus.NewDelete) + +JUCE_END_NO_SANITIZE + +} // namespace juce + +#endif // DOXYGEN diff --git a/modules/juce_audio_processors/juce_audio_processors.h b/modules/juce_audio_processors/juce_audio_processors.h index d0d8640f3d..6199e54aea 100644 --- a/modules/juce_audio_processors/juce_audio_processors.h +++ b/modules/juce_audio_processors/juce_audio_processors.h @@ -142,6 +142,7 @@ //============================================================================== #include "utilities/juce_AAXClientExtensions.h" #include "utilities/juce_VST2ClientExtensions.h" +#include "utilities/juce_VST3Interface.h" #include "utilities/juce_VST3ClientExtensions.h" #include "format_types/juce_ARACommon.h" #include "utilities/juce_ExtensionsVisitor.h" diff --git a/modules/juce_audio_processors/processors/juce_AudioProcessor.h b/modules/juce_audio_processors/processors/juce_AudioProcessor.h index 498641f821..0b8cb7e785 100644 --- a/modules/juce_audio_processors/processors/juce_AudioProcessor.h +++ b/modules/juce_audio_processors/processors/juce_AudioProcessor.h @@ -1155,8 +1155,8 @@ public: See also the helper function getXmlFromBinary() for loading settings as XML. In the case that this AudioProcessor is implementing a VST3 that has declared compatible - plugins via VST3ClientExtensions::getCompatibleClasses(), the state passed to this - function may have been created by one of these compatible plugins. + plugins via JUCE_VST3_COMPATIBLE_CLASSES, the state passed to this function may have + been created by one of these compatible plugins. If the parameter IDs of the current plugin differ from the IDs of the plugin whose state was passed to this function, you can use information from the plugin state diff --git a/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h b/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h index 897f6c7bfc..370b2b3852 100644 --- a/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h +++ b/modules/juce_audio_processors/utilities/ARA/juce_ARADebug.h @@ -36,8 +36,8 @@ #include -#ifndef JUCE_API - #define JUCE_API +#if ! (defined (JUCE_API) || defined (DOXYGEN)) + #define JUCE_API #endif #if (JucePlugin_Enable_ARA || (JUCE_PLUGINHOST_ARA && (JUCE_PLUGINHOST_VST3 || JUCE_PLUGINHOST_AU))) && (JUCE_MAC || JUCE_WINDOWS || JUCE_LINUX) diff --git a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp index 8cb875b114..60c1f7e7aa 100644 --- a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.cpp @@ -35,128 +35,11 @@ namespace juce { -std::map VST3ClientExtensions::getCompatibleParameterIds (const InterfaceId&) const +std::map VST3ClientExtensions::getCompatibleParameterIds (const VST3Interface::Id&) 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; - }); - - constexpr auto getByteFromLSB = [] (uint32_t word, int byteIndex) - { - jassert (isPositiveAndNotGreaterThan (byteIndex, 3)); - return (std::byte) ((word >> (byteIndex * 8)) & 0xff); - }; - - #if JUCE_WINDOWS - constexpr auto isWindows = true; - #else - constexpr auto isWindows = false; - #endif - - return { - getByteFromLSB (word0, isWindows ? 0 : 3), - getByteFromLSB (word0, isWindows ? 1 : 2), - getByteFromLSB (word0, isWindows ? 2 : 1), - getByteFromLSB (word0, isWindows ? 3 : 0), - - getByteFromLSB (word1, isWindows ? 2 : 3), - getByteFromLSB (word1, isWindows ? 3 : 2), - getByteFromLSB (word1, isWindows ? 0 : 1), - getByteFromLSB (word1, isWindows ? 1 : 0), - - getByteFromLSB (manufacturerCode, 3), - getByteFromLSB (manufacturerCode, 2), - getByteFromLSB (manufacturerCode, 1), - getByteFromLSB (manufacturerCode, 0), - - getByteFromLSB (pluginCode, 3), - getByteFromLSB (pluginCode, 2), - getByteFromLSB (pluginCode, 1), - getByteFromLSB (pluginCode, 0) - }; -} - -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()); @@ -167,27 +50,4 @@ uint32_t VST3ClientExtensions::convertJuceParameterId (const String& parameterId 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 e132dec412..3e7f2d334a 100644 --- a/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h +++ b/modules/juce_audio_processors/utilities/juce_VST3ClientExtensions.h @@ -41,7 +41,7 @@ namespace Steinberg using TUID = char[16]; } // namespace Steinberg -#endif +#endif // DOXYGEN namespace juce { @@ -104,36 +104,6 @@ struct VST3ClientExtensions */ virtual bool getPluginHasMainInput() const { return true; } - using InterfaceId = std::array; - - /** 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 {}; } - /** This function should return a map of VST3 parameter IDs and the JUCE parameters they map to. @@ -195,74 +165,35 @@ struct VST3ClientExtensions @endcode @param compatibleClass A plugin identifier, either for the current - plugin or one listed in getCompatibleClasses(). + plugin or one listed in JUCE_VST3_COMPATIBLE_CLASSES. 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. - When JUCE_VST3_CAN_REPLACE_VST2 is set, the - InterfaceId denoting the VST2 version of the - plugin will match the InterfaceId of the - VST3 that replaces it. In this case, you should - only include the VST2 mappings in the returned - map, assuming there are no collisions between - the VST2 parameter indices and the VST3 ParamIDs. - In the unlikely event of a collision between - the VST2 and VST3 parameter IDs, you should - inspect the state that was most recently - passed to setStateInformation() to determine - whether the host is loading a VST2 state that - requires parameter remapping. If you determine - that no remapping is necessary, you can indicate - this by returning an empty map. + compatible class. Use VST3Interface::jucePluginId() + and VST3Interface::vst2PluginId() to determine + the class IDs used by JUCE plugins. When + JUCE_VST3_CAN_REPLACE_VST2 is set, the ID + denoting the VST2 version of the plugin will + match the ID of the VST3 that replaces it. In + this case, assuming there are no collisions + between the VST2 parameter indices and the VST3 + ParamIDs you should only include the VST2 + mappings in the returned map. In the unlikely + event of a collision you should inspect the + state that was most recently passed to + setStateInformation() to determine whether the + host is loading a VST2 state that requires + parameter remapping. If you determine that no + remapping is necessary, you can indicate this by + returning an empty map. @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 + @see JUCE_VST3_COMPATIBLE_CLASSES, VST3Interface::jucePluginId, VST3Interface::vst2PluginId, VST3Interface::hexStringToId */ - virtual std::map getCompatibleParameterIds (const InterfaceId& compatibleClass) const; + virtual std::map getCompatibleParameterIds (const VST3Interface::Id& 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. - - @see 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. @@ -276,8 +207,67 @@ struct VST3ClientExtensions 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); +private: + /** Instead of overriding this function you should define the preprocessor + definition JUCE_VST3_COMPATIBLE_CLASSES as described in the docs. + + @see JUCE_VST3_COMPATIBLE_CLASSES + */ + virtual std::vector getCompatibleClasses() const final + { + return {}; + } }; +#if DOXYGEN + /** 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. + + The definition of this preprocessor must be defined at the project + level, normally in your CMake or Projucer project files. + + This information will be used to implement the IPluginCompatibility + interface. + + If JUCE_VST3_CAN_REPLACE_VST2 is enabled, the VST3 plugin will have the + same identifier as the VST2 plugin and therefore you don't need to + implement this preprocessor definition. + + This preprocessor definition can contain code that depends on any class + or function defined as part of the VST3Interface struct but should avoid + any other dependencies! + + Each compatible class is a 16-byte array that corresponds to the VST3 + interface identifier as reported by a plugins IComponent interface. + For VST2 or JUCE plugins these identifiers can be determined in the + following ways: + - Use VST3Interface::vst2PluginId() for any VST2 plugins or JUCE VST3 + plugin with JUCE_VST3_CAN_REPLACE_VST3 enabled + - Use VST3Interface::jucePluginId() for any other JUCE VST3 plugins + + Examples + + @code + // Defines a VST2 plugin this VST3 can replace + JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::vst2PluginId ('Plug', "Plugin Name") + + // Defines a VST3 plugin this VST3 can replace + JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::jucePluginId ('Manu', 'Plug') + + // Defines both a VST2 and a VST3 plugin this VST3 can replace + JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::vst2PluginId ('Plug', "Plugin Name"), VST3Interface::jucePluginId ('Manu', 'Plug') + + // Defines a non-JUCE VST3 plugin this VST3 can replace + JUCE_VST3_COMPATIBLE_CLASSES=VST3Interface::hexStringToId ("0F1E2D3C4B5A69788796A5B4C3D2E1F0") + @endcode + + If the parameter IDs between compatible versions differ + VST3ClientExtensions::getCompatibleParameterIds() should also be overridden. + + @see VST3Interface VST3ClientExtensions::getCompatibleParameterIds() + */ + #define JUCE_VST3_COMPATIBLE_CLASSES +#endif // DOXYGEN + } // namespace juce diff --git a/modules/juce_audio_processors/utilities/juce_VST3Interface.h b/modules/juce_audio_processors/utilities/juce_VST3Interface.h new file mode 100644 index 0000000000..110bed2e41 --- /dev/null +++ b/modules/juce_audio_processors/utilities/juce_VST3Interface.h @@ -0,0 +1,248 @@ +/* + ============================================================================== + + 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. + + ============================================================================== +*/ + +#pragma once + +namespace juce +{ + +/** Useful functions and classes for defining VST3 Interface Ids. + + The classes and functions in this struct are intentionally lightweight, + requiring almost no JUCE or Steinberg VST3 SDK dependencies. + + @tags{Audio} +*/ +struct VST3Interface +{ + /** 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 Type + { + ara, + controller, + compatibility, + component, + processor + }; + + /** A type storing the byte values for a unique VST3 interface identifier. */ + using Id = std::array; + + /** 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. + + @see jucePluginId, hexStringToId + */ + static Id vst2PluginId (uint32_t pluginCode, + const char* pluginName, + Type interfaceType = Type::component) + { + Id iid{}; + + iid[0] = (std::byte) 'V'; + iid[1] = (std::byte) 'S'; + iid[2] = (std::byte) std::invoke ([&] + { + switch (interfaceType) + { + case Type::controller: return 'E'; + case Type::component: return 'T'; + case Type::ara: [[fallthrough]]; + case Type::compatibility: [[fallthrough]]; + case Type::processor: break; + } + + // A VST2 plugin only has two possible 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 (size_t index = 7; index < iid.size() && *pluginName != 0; ++index) + { + iid[index] = (std::byte) std::tolower (*pluginName); + ++pluginName; + } + + #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; + } + + /** 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 + */ + static inline Id jucePluginId (uint32_t manufacturerCode, + uint32_t pluginCode, + Type interfaceType = Type::component) + { + const auto word0 = std::invoke ([&]() -> uint32_t + { + switch (interfaceType) + { + case Type::ara: [[fallthrough]]; + case Type::controller: [[fallthrough]]; + case Type::compatibility: [[fallthrough]]; + case Type::component: return 0xABCDEF01; + case Type::processor: return 0x0101ABAB; + } + + jassertfalse; + return 0; + }); + + const auto word1 = std::invoke ([&]() -> uint32_t + { + switch (interfaceType) + { + case Type::ara: return 0xA1B2C3D4; + case Type::controller: return 0x1234ABCD; + case Type::compatibility: return 0xC0DEF00D; + case Type::component: return 0x9182FAEB; + case Type::processor: return 0xABCDEF01; + } + + jassertfalse; + return 0; + }); + + constexpr auto getByteFromLSB = [] (uint32_t word, int byteIndex) + { + jassert (0 <= byteIndex && byteIndex <= 3); + return (std::byte) ((word >> (byteIndex * 8)) & 0xff); + }; + + #if JUCE_WINDOWS + constexpr auto isWindows = true; + #else + constexpr auto isWindows = false; + #endif + + return { + getByteFromLSB (word0, isWindows ? 0 : 3), + getByteFromLSB (word0, isWindows ? 1 : 2), + getByteFromLSB (word0, isWindows ? 2 : 1), + getByteFromLSB (word0, isWindows ? 3 : 0), + + getByteFromLSB (word1, isWindows ? 2 : 3), + getByteFromLSB (word1, isWindows ? 3 : 2), + getByteFromLSB (word1, isWindows ? 0 : 1), + getByteFromLSB (word1, isWindows ? 1 : 0), + + getByteFromLSB (manufacturerCode, 3), + getByteFromLSB (manufacturerCode, 2), + getByteFromLSB (manufacturerCode, 1), + getByteFromLSB (manufacturerCode, 0), + + getByteFromLSB (pluginCode, 3), + getByteFromLSB (pluginCode, 2), + getByteFromLSB (pluginCode, 1), + getByteFromLSB (pluginCode, 0) + }; + } + + /** 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; +}; + +} // namespace juce