diff --git a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
index 35379d7a5e..6a032fa594 100644
--- a/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
+++ b/examples/DemoRunner/Builds/Android/app/CMakeLists.txt
@@ -748,6 +748,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
@@ -3263,6 +3265,8 @@ set_source_files_properties(
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
index d34954a154..f80394e608 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj
@@ -947,6 +947,9 @@
true
+
+ true
+
true
@@ -3552,6 +3555,7 @@
+
diff --git a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
index 243b2c5399..8a42e5619d 100644
--- a/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2019/DemoRunner_App.vcxproj.filters
@@ -1639,6 +1639,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -5250,6 +5253,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
index b862217d2c..7b3c5bc01a 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj
@@ -947,6 +947,9 @@
true
+
+ true
+
true
@@ -3552,6 +3555,7 @@
+
diff --git a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
index 0d8aaf63bc..0269f158b0 100644
--- a/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
+++ b/examples/DemoRunner/Builds/VisualStudio2022/DemoRunner_App.vcxproj.filters
@@ -1639,6 +1639,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -5250,6 +5253,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
index 682db777df..d14a0bf159 100644
--- a/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPerformanceTest/Builds/Android/app/CMakeLists.txt
@@ -703,6 +703,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
@@ -2901,6 +2903,8 @@ set_source_files_properties(
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
index bb4feb7fec..723a414e57 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj
@@ -907,6 +907,9 @@
true
+
+ true
+
true
@@ -3124,6 +3127,7 @@
+
diff --git a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
index 6ee29f4608..d9891e52d2 100644
--- a/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
+++ b/extras/AudioPerformanceTest/Builds/VisualStudio2022/AudioPerformanceTest_App.vcxproj.filters
@@ -1456,6 +1456,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4608,6 +4611,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
index b4b8f706f5..9e780dd435 100644
--- a/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
+++ b/extras/AudioPluginHost/Builds/Android/app/CMakeLists.txt
@@ -736,6 +736,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
@@ -3087,6 +3089,8 @@ set_source_files_properties(
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
index bc03d70f9f..0e15fa3ef8 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj
@@ -915,6 +915,9 @@
true
+
+ true
+
true
@@ -3304,6 +3307,7 @@
+
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
index 116cf3c080..c9c303abc8 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2019/AudioPluginHost_App.vcxproj.filters
@@ -1531,6 +1531,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4884,6 +4887,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
index 6ddce8d84f..8defa769a0 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj
@@ -915,6 +915,9 @@
true
+
+ true
+
true
@@ -3304,6 +3307,7 @@
+
diff --git a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
index 08e12d981f..00323eac0b 100644
--- a/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
+++ b/extras/AudioPluginHost/Builds/VisualStudio2022/AudioPluginHost_App.vcxproj.filters
@@ -1531,6 +1531,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4884,6 +4887,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/Build/CMake/JUCEHelperTargets.cmake b/extras/Build/CMake/JUCEHelperTargets.cmake
index 30ed5284fd..e7002ae1c7 100644
--- a/extras/Build/CMake/JUCEHelperTargets.cmake
+++ b/extras/Build/CMake/JUCEHelperTargets.cmake
@@ -99,6 +99,7 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
-Wno-implicit-fallthrough
-Wno-maybe-uninitialized
-Wno-ignored-qualifiers
+ -Wno-multichar
-Wswitch-enum
-Wredundant-decls
-Wno-strict-overflow
diff --git a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
index 984b630ad2..8c6cb29e72 100644
--- a/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
+++ b/extras/NetworkGraphicsDemo/Builds/Android/app/CMakeLists.txt
@@ -707,6 +707,8 @@ add_library( ${BINARY_NAME}
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
@@ -2985,6 +2987,8 @@ set_source_files_properties(
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/stringconvert.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/uid.h"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp"
+ "../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.cpp"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstbus.h"
"../../../../../modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/vstcomponent.cpp"
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
index 3569fecde8..dbd231cf59 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj
@@ -907,6 +907,9 @@
true
+
+ true
+
true
@@ -3215,6 +3218,7 @@
+
diff --git a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
index 259e43ed02..8540038cb4 100644
--- a/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
+++ b/extras/NetworkGraphicsDemo/Builds/VisualStudio2022/NetworkGraphicsDemo_App.vcxproj.filters
@@ -1486,6 +1486,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4749,6 +4752,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp
index 5e91e9bfe7..4b298ffc3a 100644
--- a/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp
+++ b/extras/Projucer/Source/ProjectSaving/jucer_ProjectExporter.cpp
@@ -954,6 +954,7 @@ ProjectExporter::BuildConfiguration::BuildConfiguration (Project& p, const Value
"-Wno-maybe-uninitialized",
"-Wredundant-decls",
"-Wno-strict-overflow",
+ "-Wno-multichar",
"-Wshadow" });
}
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
index 47d67d5b44..b29b374f90 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj
@@ -923,6 +923,9 @@
true
+
+ true
+
true
@@ -3400,6 +3403,7 @@
+
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
index 43aedc6ab7..557924d8bf 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2019/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -1552,6 +1552,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4998,6 +5001,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
index 3159363a5a..c5f60508cd 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj
@@ -923,6 +923,9 @@
true
+
+ true
+
true
@@ -3400,6 +3403,7 @@
+
diff --git a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
index f2c1c612b7..977ae82575 100644
--- a/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
+++ b/extras/UnitTestRunner/Builds/VisualStudio2022/UnitTestRunner_ConsoleApp.vcxproj.filters
@@ -1552,6 +1552,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4998,6 +5001,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
index 283f2ea7c9..7a022809df 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj
@@ -906,6 +906,9 @@
true
+
+ true
+
true
@@ -3191,6 +3194,7 @@
+
diff --git a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
index 5c908a7ecc..7ea6ca93da 100644
--- a/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
+++ b/extras/WindowsDLL/Builds/VisualStudio2022/WindowsDLL_StaticLibrary.vcxproj.filters
@@ -1483,6 +1483,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
@@ -4716,6 +4719,9 @@
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
+ JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst\utility
+
JUCE Modules\juce_audio_processors\format_types\VST3_SDK\public.sdk\source\vst
diff --git a/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h
index c73ef16a79..1e7744f94c 100644
--- a/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h
+++ b/modules/juce_audio_plugin_client/detail/juce_PluginUtilities.h
@@ -66,10 +66,6 @@ struct PluginUtilities
return hostType;
}
- #ifndef JUCE_VST3_CAN_REPLACE_VST2
- #define JUCE_VST3_CAN_REPLACE_VST2 1
- #endif
-
// NB: Nasty old-fashioned code in here because it's copied from the Steinberg example code.
static void getUUIDForVST2ID (bool forControllerUID, uint8 uuid[16])
{
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 568d0c6778..db7eea776a 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
@@ -64,24 +64,6 @@ JUCE_BEGIN_NO_SANITIZE ("vptr")
#include
#include
-#ifndef JUCE_VST3_CAN_REPLACE_VST2
- #define JUCE_VST3_CAN_REPLACE_VST2 1
-#endif
-
-#if JUCE_VST3_CAN_REPLACE_VST2
-
- #if ! JUCE_MSVC && ! defined (__cdecl)
- #define __cdecl
- #endif
-
- namespace Vst2
- {
- struct AEffect;
- #include "pluginterfaces/vst2.x/vstfxstore.h"
- }
-
-#endif
-
#ifndef JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS
#if JucePlugin_WantsMidiInput
#define JUCE_VST3_EMULATE_MIDI_CC_WITH_PARAMETERS 1
@@ -2824,102 +2806,22 @@ public:
}
//==============================================================================
- #if JUCE_VST3_CAN_REPLACE_VST2
- bool loadVST2VstWBlock (const char* data, int size)
- {
- jassert (ByteOrder::bigEndianInt ("VstW") == htonl ((uint32) readUnaligned (data)));
- jassert (1 == htonl ((uint32) readUnaligned (data + 8))); // version should be 1 according to Steinberg's docs
-
- auto headerLen = (int) htonl ((uint32) readUnaligned (data + 4)) + 8;
- return loadVST2CcnKBlock (data + headerLen, size - headerLen);
- }
-
- bool loadVST2CcnKBlock (const char* data, int size)
- {
- auto* bank = reinterpret_cast (data);
-
- jassert (ByteOrder::bigEndianInt ("CcnK") == htonl ((uint32) bank->chunkMagic));
- jassert (ByteOrder::bigEndianInt ("FBCh") == htonl ((uint32) bank->fxMagic));
- jassert (htonl ((uint32) bank->version) == 1 || htonl ((uint32) bank->version) == 2);
- jassert (JucePlugin_VSTUniqueID == htonl ((uint32) bank->fxID));
-
- setStateInformation (bank->content.data.chunk,
- jmin ((int) (size - (bank->content.data.chunk - data)),
- (int) htonl ((uint32) bank->content.data.size)));
- return true;
- }
-
- bool loadVST3PresetFile (const char* data, int size)
- {
- if (size < 48)
- return false;
-
- // At offset 4 there's a little-endian version number which seems to typically be 1
- // At offset 8 there's 32 bytes the SDK calls "ASCII-encoded class id"
- auto chunkListOffset = (int) ByteOrder::littleEndianInt (data + 40);
- jassert (memcmp (data + chunkListOffset, "List", 4) == 0);
- auto entryCount = (int) ByteOrder::littleEndianInt (data + chunkListOffset + 4);
- jassert (entryCount > 0);
-
- for (int i = 0; i < entryCount; ++i)
- {
- auto entryOffset = chunkListOffset + 8 + 20 * i;
-
- if (entryOffset + 20 > size)
- return false;
-
- if (memcmp (data + entryOffset, "Comp", 4) == 0)
- {
- // "Comp" entries seem to contain the data.
- auto chunkOffset = ByteOrder::littleEndianInt64 (data + entryOffset + 4);
- auto chunkSize = ByteOrder::littleEndianInt64 (data + entryOffset + 12);
-
- if (static_cast (chunkOffset + chunkSize) > static_cast (size))
- {
- jassertfalse;
- return false;
- }
-
- loadVST2VstWBlock (data + chunkOffset, (int) chunkSize);
- }
- }
-
- return true;
- }
-
- bool loadVST2CompatibleState (const char* data, int size)
- {
- if (size < 4)
- return false;
-
- auto header = htonl ((uint32) readUnaligned (data));
-
- if (header == ByteOrder::bigEndianInt ("VstW"))
- return loadVST2VstWBlock (data, size);
-
- if (header == ByteOrder::bigEndianInt ("CcnK"))
- return loadVST2CcnKBlock (data, size);
-
- if (memcmp (data, "VST3", 4) == 0)
- {
- // In Cubase 5, when loading VST3 .vstpreset files,
- // we get the whole content of the files to load.
- // In Cubase 7 we get just the contents within and
- // we go directly to the loadVST2VstW codepath instead.
- return loadVST3PresetFile (data, size);
- }
-
- return false;
- }
- #endif
-
- void loadStateData (const void* data, int size)
+ bool shouldTryToLoadVst2State()
{
#if JUCE_VST3_CAN_REPLACE_VST2
- if (loadVST2CompatibleState ((const char*) data, size))
- return;
+ return true;
+ #else
+ return false;
+ #endif
+ }
+
+ bool shouldWriteStateWithVst2Compatibility()
+ {
+ #if JUCE_VST3_CAN_REPLACE_VST2
+ return true;
+ #else
+ return false;
#endif
- setStateInformation (data, size);
}
bool readFromMemoryStream (IBStream* state)
@@ -2952,7 +2854,7 @@ public:
if (block.getSize() >= 5 && memcmp (block.getData(), "VC2!E", 5) == 0)
return false;
- loadStateData (block.getData(), (int) block.getSize());
+ setStateInformation (block.getData(), (int) block.getSize());
return true;
}
@@ -2984,10 +2886,21 @@ public:
if (dataSize <= 0 || dataSize >= 0x7fffffff)
return false;
- loadStateData (allData.getData(), (int) dataSize);
+ setStateInformation (allData.getData(), (int) dataSize);
return true;
}
+ bool readVst2State (IBStream* state)
+ {
+ if (auto vst2State = VST3::tryVst2StateLoad (*state))
+ {
+ setStateInformation (vst2State->chunk.data(), (int) vst2State->chunk.size());
+ return true;
+ }
+
+ return false;
+ }
+
tresult PLUGIN_API setState (IBStream* state) override
{
// The VST3 spec requires that this function is called from the UI thread.
@@ -2999,36 +2912,41 @@ public:
FUnknownPtr stateRefHolder (state); // just in case the caller hasn't properly ref-counted the stream object
- if (state->seek (0, IBStream::kIBSeekSet, nullptr) == kResultTrue)
+ const auto seekToBeginningOfStream = [&]
{
- if (! detail::PluginUtilities::getHostType().isFruityLoops() && readFromMemoryStream (state))
- return kResultTrue;
+ return state->seek (0, IBStream::kIBSeekSet, nullptr) == kResultTrue;
+ };
- if (readFromUnknownStream (state))
- return kResultTrue;
- }
+ if (seekToBeginningOfStream() && shouldTryToLoadVst2State() && readVst2State (state))
+ return kResultTrue;
+
+ if (seekToBeginningOfStream() && ! detail::PluginUtilities::getHostType().isFruityLoops() && readFromMemoryStream (state))
+ return kResultTrue;
+
+ if (seekToBeginningOfStream() && readFromUnknownStream (state))
+ return kResultTrue;
return kResultFalse;
}
- #if JUCE_VST3_CAN_REPLACE_VST2
- static tresult writeVST2Header (IBStream* state, bool bypassed)
+ tresult getStateWithVst2Compatibility (const MemoryBlock& dataChunk, IBStream& outState)
{
- auto writeVST2IntToState = [state] (uint32 n)
- {
- auto t = (int32) htonl (n);
- return state->write (&t, 4);
- };
+ VST3::Vst2xState vst2State;
- auto status = writeVST2IntToState (ByteOrder::bigEndianInt ("VstW"));
+ vst2State.chunk.resize (dataChunk.getSize());
+ std::copy (dataChunk.begin(), dataChunk.end(), vst2State.chunk.begin());
- if (status == kResultOk) status = writeVST2IntToState (8); // header size
- if (status == kResultOk) status = writeVST2IntToState (1); // version
- if (status == kResultOk) status = writeVST2IntToState (bypassed ? 1 : 0); // bypass
+ vst2State.fxUniqueID = JucePlugin_VSTUniqueID;
+ vst2State.fxVersion = JucePlugin_VersionCode;
+ vst2State.isBypassed = isBypassed();
- return status;
+ if (VST3::writeVst2State (vst2State, outState))
+ return kResultTrue;
+
+ // Please inform the JUCE team if you hit this assertion
+ jassertfalse;
+ return kResultFalse;
}
- #endif
tresult PLUGIN_API getState (IBStream* state) override
{
@@ -3038,29 +2956,11 @@ public:
MemoryBlock mem;
getStateInformation (mem);
- #if JUCE_VST3_CAN_REPLACE_VST2
- tresult status = writeVST2Header (state, isBypassed());
+ if (mem.isEmpty())
+ return kResultFalse;
- if (status != kResultOk)
- return status;
-
- const int bankBlockSize = 160;
- Vst2::fxBank bank;
-
- zerostruct (bank);
- bank.chunkMagic = (int32) htonl (ByteOrder::bigEndianInt ("CcnK"));
- bank.byteSize = (int32) htonl (bankBlockSize - 8 + (unsigned int) mem.getSize());
- bank.fxMagic = (int32) htonl (ByteOrder::bigEndianInt ("FBCh"));
- bank.version = (int32) htonl (2);
- bank.fxID = (int32) htonl (JucePlugin_VSTUniqueID);
- bank.fxVersion = (int32) htonl (JucePlugin_VersionCode);
- bank.content.data.size = (int32) htonl ((unsigned int) mem.getSize());
-
- status = state->write (&bank, bankBlockSize);
-
- if (status != kResultOk)
- return status;
- #endif
+ if (shouldWriteStateWithVst2Compatibility())
+ return getStateWithVst2Compatibility (mem, *state);
return state->write (mem.getData(), (Steinberg::int32) mem.getSize());
}
diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp
new file mode 100644
index 0000000000..a6ccdb0098
--- /dev/null
+++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.cpp
@@ -0,0 +1,633 @@
+//------------------------------------------------------------------------
+// Flags : clang-format SMTGSequencer
+// Project : VST3 SDK
+// Filename : public.sdk/source/vst/utility/vst2persistence.cpp
+// Created by : Steinberg, 12/2019
+// Description : vst2 persistence helper
+//
+//------------------------------------------------------------------------
+// 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 "public.sdk/source/vst/utility/vst2persistence.h"
+#include "pluginterfaces/base/fplatform.h"
+#include
+
+//------------------------------------------------------------------------
+namespace VST3 {
+namespace {
+namespace IO {
+
+//------------------------------------------------------------------------
+enum class Error
+{
+ NoError,
+ Unknown,
+ EndOfFile,
+ BufferToBig,
+ NotAllowed,
+ InvalidArgument,
+};
+
+//------------------------------------------------------------------------
+enum class SeekMode
+{
+ Set,
+ End,
+ Current
+};
+
+//------------------------------------------------------------------------
+struct Result
+{
+ Error error {Error::Unknown};
+ uint64_t bytes {0u};
+
+ Result () noexcept = default;
+ Result (Error error, uint64_t bytes = 0) noexcept : error (error), bytes (bytes) {}
+
+ operator bool () const noexcept { return error == Error::NoError; }
+};
+
+//------------------------------------------------------------------------
+struct ReadBufferDesc
+{
+ const uint64_t bytes;
+ void* ptr;
+};
+
+//------------------------------------------------------------------------
+struct WriteBufferDesc
+{
+ const uint64_t bytes;
+ const void* ptr;
+};
+
+//------------------------------------------------------------------------
+template
+class ByteOrderStream
+{
+public:
+//------------------------------------------------------------------------
+ ByteOrderStream (Steinberg::IBStream& stream) noexcept : stream (stream) {}
+ ByteOrderStream (ByteOrderStream&&) noexcept = delete;
+ ByteOrderStream& operator= (ByteOrderStream&&) noexcept = delete;
+ ByteOrderStream (const ByteOrderStream&) noexcept = delete;
+ ByteOrderStream& operator= (const ByteOrderStream&) noexcept = delete;
+
+ inline Result operator<< (const std::string& input) noexcept;
+ inline Result operator>> (std::string& output) noexcept;
+
+ template
+ inline Result operator<< (const T& input) noexcept;
+ template
+ inline Result operator>> (T& output) const noexcept;
+
+ inline Result read (const ReadBufferDesc& buffer) const noexcept;
+ inline Result write (const WriteBufferDesc& buffer) noexcept;
+ inline Result seek (SeekMode mode, int64_t bytes) const noexcept;
+ inline Result tell () const noexcept;
+
+//------------------------------------------------------------------------
+private:
+ template
+ inline Result swapAndWrite (const uint8_t* buffer) noexcept;
+ inline void swap (uint8_t* buffer, uint64_t size) const noexcept;
+ Steinberg::IBStream& stream;
+};
+
+//------------------------------------------------------------------------
+using LittleEndianStream = ByteOrderStream;
+using BigEndianStream = ByteOrderStream;
+using NativeEndianStream = ByteOrderStream;
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::read (const ReadBufferDesc& buffer) const noexcept
+{
+ if (buffer.bytes > static_cast (std::numeric_limits::max ()))
+ return Result (Error::BufferToBig);
+ Steinberg::int32 readBytes = 0;
+ auto tres = stream.read (buffer.ptr, static_cast (buffer.bytes), &readBytes);
+ if (tres != Steinberg::kResultTrue)
+ return Result (Error::Unknown);
+ assert (readBytes >= 0);
+ return Result {Error::NoError, static_cast (readBytes)};
+}
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::write (const WriteBufferDesc& buffer) noexcept
+{
+ if (buffer.bytes > static_cast (std::numeric_limits::max ()))
+ return Result (Error::BufferToBig);
+ Steinberg::int32 writtenBytes = 0;
+ auto tres = stream.write (const_cast (buffer.ptr),
+ static_cast (buffer.bytes), &writtenBytes);
+ if (tres != Steinberg::kResultTrue)
+ return Result (Error::Unknown);
+ assert (writtenBytes >= 0);
+ return Result {Error::NoError, static_cast (writtenBytes)};
+}
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::seek (SeekMode mode, int64_t bytes) const noexcept
+{
+ Steinberg::int32 seekMode = 0;
+ switch (mode)
+ {
+ case SeekMode::Set: seekMode = Steinberg::IBStream::kIBSeekSet; break;
+ case SeekMode::Current: seekMode = Steinberg::IBStream::kIBSeekCur; break;
+ case SeekMode::End: seekMode = Steinberg::IBStream::kIBSeekEnd; break;
+ }
+ Steinberg::int64 seekRes = 0;
+ auto tres = stream.seek (static_cast (bytes), seekMode, &seekRes);
+ if (tres != Steinberg::kResultTrue || seekRes < 0)
+ return Result {Error::Unknown};
+ return Result (Error::NoError, static_cast (seekRes));
+}
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::tell () const noexcept
+{
+ Steinberg::int64 tellRes = 0;
+ auto tres = stream.tell (&tellRes);
+ if (tres != Steinberg::kResultTrue || tellRes < 0)
+ return Result {Error::Unknown};
+ return Result {Error::NoError, static_cast (tellRes)};
+}
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::operator<< (const std::string& input) noexcept
+{
+ auto res = *this << static_cast (input.length ());
+ if (!res)
+ return res;
+ res = stream.write (const_cast (static_cast (input.data ())),
+ static_cast (input.length ()));
+ res.bytes += sizeof (uint64_t);
+ return res;
+}
+
+//------------------------------------------------------------------------
+template
+inline Result ByteOrderStream::operator>> (std::string& output) noexcept
+{
+ uint64_t length;
+ auto res = *this >> length;
+ if (!res)
+ return res;
+ output.resize (length);
+ if (length > 0)
+ {
+ res = stream.read (&output.front (), static_cast (length));
+ res.bytes += sizeof (uint64_t);
+ }
+ return res;
+}
+
+//------------------------------------------------------------------------
+template
+template
+inline Result ByteOrderStream::operator<< (const T& input) noexcept
+{
+ static_assert (std::is_standard_layout::value, "Only standard layout types allowed");
+ // with C++17: if constexpr (StreamByteOrder == BYTEORDER)
+ if (constexpr bool tmp = (StreamByteOrder == BYTEORDER))
+ return write (WriteBufferDesc {sizeof (T), static_cast (&input)});
+
+ return swapAndWrite (reinterpret_cast (&input));
+}
+
+//------------------------------------------------------------------------
+template
+template
+inline Result ByteOrderStream::operator>> (T& output) const noexcept
+{
+ static_assert (std::is_standard_layout::value, "Only standard layout types allowed");
+ auto res = read (ReadBufferDesc {sizeof (T), &output});
+ // with C++17: if constexpr (StreamByteOrder == BYTEORDER)
+ if (constexpr bool tmp = (StreamByteOrder == BYTEORDER))
+ return res;
+
+ swap (reinterpret_cast (&output), res.bytes);
+ return res;
+}
+
+//------------------------------------------------------------------------
+template
+template
+inline Result ByteOrderStream::swapAndWrite (const uint8_t* buffer) noexcept
+{
+ // with C++17: if constexpr (_size > 1)
+ if (constexpr bool tmp2 = (_size > 1))
+ {
+ int8_t tmp[_size];
+
+ constexpr auto halfSize = _size / 2;
+ auto size = _size;
+ auto low = buffer;
+ auto high = buffer + size - 1;
+
+ while (size > halfSize)
+ {
+ tmp[size - 2] = buffer[(_size - size) + 1];
+ tmp[(_size - size) + 1] = buffer[size - 2];
+ tmp[_size - size] = *high;
+ tmp[size - 1] = *low;
+ low += 2;
+ high -= 2;
+ size -= 2;
+ }
+ return write (WriteBufferDesc {_size, tmp});
+ }
+ return write (WriteBufferDesc {1, buffer});
+}
+
+//------------------------------------------------------------------------
+template
+inline void ByteOrderStream::swap (uint8_t* buffer, uint64_t size) const noexcept
+{
+ if (size < 2)
+ return;
+ auto low = buffer;
+ auto high = buffer + size - 1;
+ while (size >= 2)
+ {
+ auto tmp = *low;
+ *low = *high;
+ *high = tmp;
+ low += 2;
+ high -= 2;
+ size -= 2;
+ }
+}
+
+//------------------------------------------------------------------------
+} // IO
+
+//------------------------------------------------------------------------
+constexpr int32_t cMagic = 'CcnK';
+constexpr int32_t bankMagic = 'FxBk';
+constexpr int32_t privateChunkID = 'VstW';
+constexpr int32_t chunkBankMagic = 'FBCh';
+constexpr int32_t programMagic = 'FxCk';
+constexpr int32_t chunkProgramMagic = 'FPCh';
+
+//------------------------------------------------------------------------
+Optional loadProgram (const IO::BigEndianStream& state,
+ const Optional& vst2xUniqueID)
+{
+ Vst2xProgram program;
+ int32_t id;
+ if (!(state >> id))
+ return {};
+ if (id != cMagic)
+ return {};
+ int32_t bankSize;
+ if (!(state >> bankSize))
+ return {};
+ int32_t fxMagic;
+ if (!(state >> fxMagic))
+ return {};
+ if (!(fxMagic == programMagic || fxMagic == chunkProgramMagic))
+ return {};
+ int32_t formatVersion;
+ if (!(state >> formatVersion))
+ return {};
+ int32_t fxId;
+ if (!(state >> fxId))
+ return {};
+ if (vst2xUniqueID && fxId != *vst2xUniqueID)
+ return {};
+ int32_t fxVersion;
+ if (!(state >> fxVersion))
+ return {};
+ int32_t numParams;
+ if (!(state >> numParams))
+ return {};
+ if (numParams < 0)
+ return {};
+ char name[29];
+ if (!state.read ({28, name}))
+ return {};
+ name[28] = 0;
+ program.name = name;
+ program.fxUniqueID = fxId;
+ program.fxVersion = fxVersion;
+ if (fxMagic == chunkProgramMagic)
+ {
+ uint32_t chunkSize;
+ if (!(state >> chunkSize))
+ return {};
+ program.chunk.resize (chunkSize);
+ if (!state.read ({chunkSize, program.chunk.data ()}))
+ return {};
+ }
+ else
+ {
+ program.values.resize (numParams);
+ float paramValue;
+ for (int32_t i = 0; i < numParams; ++i)
+ {
+ if (!(state >> paramValue))
+ return {};
+ program.values[i] = paramValue;
+ }
+ }
+ return {std::move (program)};
+}
+
+//------------------------------------------------------------------------
+bool loadPrograms (Steinberg::IBStream& stream, Vst2xState::Programs& programs,
+ const Optional& vst2xUniqueID)
+{
+ IO::BigEndianStream state (stream);
+
+ for (auto& program : programs)
+ {
+ if (auto prg = loadProgram (state, vst2xUniqueID))
+ std::swap (program, *prg);
+ else
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
+template
+IO::Error streamSizeWriter (StreamT& stream, Proc proc)
+{
+ auto startPos = stream.tell ();
+ if (startPos.error != IO::Error::NoError)
+ return startPos.error;
+ auto res = stream << static_cast (0); // placeholder
+ if (!res)
+ return res.error;
+ auto procRes = proc ();
+ if (procRes != IO::Error::NoError)
+ return procRes;
+ auto endPos = stream.tell ();
+ if (endPos.error != IO::Error::NoError)
+ return endPos.error;
+ auto size = (endPos.bytes - startPos.bytes) - 4;
+ auto typeSize = static_cast (size);
+ if (size != static_cast (typeSize))
+ return IO::Error::Unknown;
+ res = stream.seek (IO::SeekMode::Set, startPos.bytes);
+ if (!res)
+ return res.error;
+ res = (stream << typeSize);
+ if (!res)
+ return res.error;
+ res = stream.seek (IO::SeekMode::Set, endPos.bytes);
+ return res.error;
+}
+
+//------------------------------------------------------------------------
+template
+IO::Error writePrograms (StreamT& stream, const Vst2xState::Programs& programs)
+{
+ for (const auto& program : programs)
+ {
+ auto res = stream << cMagic;
+ if (!res)
+ return res.error;
+ res = streamSizeWriter (stream, [&] () {
+ bool writeChunk = !program.chunk.empty ();
+ if (!(res = stream << (writeChunk ? chunkProgramMagic : programMagic)))
+ return res.error;
+ int32_t version = 1;
+ if (!(res = stream << version))
+ return res.error;
+ if (!(res = stream << program.fxUniqueID))
+ return res.error;
+ int32_t fxVersion = program.fxVersion;
+ if (!(res = stream << fxVersion))
+ return res.error;
+ uint32_t numParams = static_cast (program.values.size ());
+ if (!(res = stream << numParams))
+ return res.error;
+ auto programName = program.name;
+ programName.resize (28);
+ for (auto c : programName)
+ {
+ if (!(res = stream << c))
+ return res.error;
+ }
+ if (writeChunk)
+ {
+ if (!(res = stream << static_cast (program.chunk.size ())))
+ return res.error;
+ if (!(res = stream.write ({program.chunk.size (), program.chunk.data ()})))
+ return res.error;
+ }
+ else
+ {
+ for (auto value : program.values)
+ {
+ if (!(res = stream << value))
+ return res.error;
+ }
+ }
+ return IO::Error::NoError;
+ });
+ if (res.error != IO::Error::NoError)
+ return res.error;
+ }
+ return IO::Error::NoError;
+}
+
+//------------------------------------------------------------------------
+} // anonymous
+
+//------------------------------------------------------------------------
+Optional tryVst2StateLoad (Steinberg::IBStream& stream,
+ Optional vst2xUniqueID) noexcept
+{
+ Vst2xState result;
+
+ IO::BigEndianStream state (stream);
+ int32_t version;
+ int32_t size;
+ int32_t id;
+ if (!(state >> id))
+ return {};
+ if (id == privateChunkID)
+ {
+ if (!(state >> size))
+ return {};
+ if (!(state >> version))
+ return {};
+ int32_t bypass;
+ if (!(state >> bypass))
+ return {};
+ result.isBypassed = bypass ? true : false;
+ if (!(state >> id))
+ return {};
+ }
+ if (id != cMagic)
+ return {};
+ int32_t bankSize;
+ if (!(state >> bankSize))
+ return {};
+ int32_t fxMagic;
+ if (!(state >> fxMagic))
+ return {};
+ if (!(fxMagic == bankMagic || fxMagic == chunkBankMagic))
+ return {};
+ int32_t bankVersion;
+ if (!(state >> bankVersion))
+ return {};
+ int32_t fxId;
+ if (!(state >> fxId))
+ return {};
+ if (vst2xUniqueID && fxId != *vst2xUniqueID)
+ return {};
+ result.fxUniqueID = fxId;
+ int32_t fxVersion;
+ if (!(state >> fxVersion))
+ return {};
+ result.fxVersion = fxVersion;
+
+ int32_t numPrograms;
+ if (!(state >> numPrograms))
+ return {};
+ if (numPrograms < 1)
+ return {};
+
+ int32_t currentProgram = 0;
+ if (bankVersion >= 1)
+ {
+ if (!(state >> currentProgram))
+ return {};
+ state.seek (IO::SeekMode::Current, 124); // future
+ }
+ result.currentProgram = currentProgram;
+ if (fxMagic == bankMagic)
+ {
+ result.programs.resize (numPrograms);
+ if (!loadPrograms (stream, result.programs, vst2xUniqueID))
+ return {};
+ assert (static_cast (result.programs.size ()) > currentProgram);
+ }
+ else
+ {
+ uint32_t chunkSize;
+ if (!(state >> chunkSize))
+ return {};
+ if (chunkSize == 0)
+ return {};
+ result.chunk.resize (chunkSize);
+ if (!state.read ({chunkSize, result.chunk.data ()}))
+ return {};
+ }
+ return {std::move (result)};
+}
+
+//------------------------------------------------------------------------
+bool writeVst2State (const Vst2xState& state, Steinberg::IBStream& _stream,
+ bool writeBypassState) noexcept
+{
+ IO::BigEndianStream stream (_stream);
+ if (writeBypassState)
+ {
+ if (!(stream << privateChunkID))
+ return false;
+ if (streamSizeWriter (stream, [&] () {
+ uint32_t version = 1;
+ auto res = (stream << version);
+ if (!res)
+ return res.error;
+ int32_t bypass = state.isBypassed ? 1 : 0;
+ return (stream << bypass).error;
+ }) != IO::Error::NoError)
+ {
+ return false;
+ }
+ }
+ if (!(stream << cMagic))
+ {
+ return false;
+ }
+ if (streamSizeWriter (stream, [&] () {
+ bool writeChunk = !state.chunk.empty ();
+ IO::Result res;
+ if (!(res = (stream << (writeChunk ? chunkBankMagic : bankMagic))))
+ return res.error;
+ int32_t bankVersion = 2;
+ if (!(res = (stream << bankVersion)))
+ return res.error;
+ if (!(res = (stream << state.fxUniqueID)))
+ return res.error;
+ if (!(res = (stream << state.fxVersion)))
+ return res.error;
+ int32_t numPrograms = writeChunk ? 1 : static_cast (state.programs.size ());
+ if (!(res = (stream << numPrograms)))
+ return res.error;
+ if (bankVersion > 1)
+ {
+ if (!(res = (stream << state.currentProgram)))
+ return res.error;
+ // write 124 zero bytes
+ uint8_t byte = 0;
+ for (uint32_t i = 0; i < 124; ++i)
+ if (!(res = (stream << byte)))
+ return res.error;
+ }
+ if (writeChunk)
+ {
+ auto chunkSize = static_cast (state.chunk.size ());
+ if (!(res = (stream << chunkSize)))
+ return res.error;
+ stream.write ({state.chunk.size (), state.chunk.data ()});
+ }
+ else
+ {
+ writePrograms (stream, state.programs);
+ }
+ return IO::Error::NoError;
+ }) != IO::Error::NoError)
+ {
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------
+Optional tryVst2ProgramLoad (Steinberg::IBStream& stream,
+ Optional vst2xUniqueID) noexcept
+{
+ IO::BigEndianStream state (stream);
+ return loadProgram (state, vst2xUniqueID);
+}
+
+//------------------------------------------------------------------------
+} // VST3
diff --git a/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h
new file mode 100644
index 0000000000..b731cc6970
--- /dev/null
+++ b/modules/juce_audio_processors/format_types/VST3_SDK/public.sdk/source/vst/utility/vst2persistence.h
@@ -0,0 +1,123 @@
+//------------------------------------------------------------------------
+// Flags : clang-format SMTGSequencer
+// Project : VST3 SDK
+// Filename : public.sdk/source/vst/utility/vst2persistence.h
+// Created by : Steinberg, 12/2019
+// Description : vst2 persistence helper
+//
+//------------------------------------------------------------------------
+// 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.
+//-----------------------------------------------------------------------------
+
+#pragma once
+
+#include "public.sdk/source/vst/utility/optional.h"
+#include "pluginterfaces/base/ibstream.h"
+#include
+#include
+
+//------------------------------------------------------------------------
+namespace VST3 {
+
+//------------------------------------------------------------------------
+using Vst2xChunk = std::vector;
+
+//------------------------------------------------------------------------
+/** structure holding the content of a vst2 fxp format stream
+ *
+ * either the values member is valid or the chunk member but not both
+ */
+struct Vst2xProgram
+{
+ using ProgramValues = std::vector;
+ ProgramValues values;
+ Vst2xChunk chunk;
+ int32_t fxUniqueID {0};
+ int32_t fxVersion {0};
+ std::string name;
+};
+
+//------------------------------------------------------------------------
+/** structure holding the content of a vst2 fxb format stream
+ *
+ * either the programs member is valid or the chunk member but not both
+ */
+struct Vst2xState
+{
+ using Programs = std::vector;
+ Programs programs;
+ Vst2xChunk chunk;
+
+ int32_t fxUniqueID {0};
+ int32_t fxVersion {0};
+ int32_t currentProgram {0};
+ bool isBypassed {false};
+};
+
+//------------------------------------------------------------------------
+/** Try loading the state from an old vst2 fxb format stream
+ *
+ * If successfully loaded, the state has either a chunk or programs but not both
+ * The Vst2xState::isBypassed boolean will be set if a Steinberg host has written the state into a
+ * project and the plug-in was bypassed.
+ *
+ * @param stream the input stream
+ * @param vst2xUniqueID vst2 unique id expected to be stored in the stream [optional]. If present
+ * the fxb unique id header entry must be the same as this otherwise the
+ * return value is empty.
+ * @return on success the optional has a Vst2xState object with the data
+ */
+Optional tryVst2StateLoad (Steinberg::IBStream& stream,
+ Optional vst2xUniqueID = {}) noexcept;
+
+//------------------------------------------------------------------------
+/** Write a vst2 fxb stream
+ *
+ * Writes the state into stream as a vst2 fxb format
+ *
+ * @param state the state which should be written
+ * @param stream the stream where the state should be written into
+ * @param writeBypassState write extra chunk with bypass state
+ * @return true on success
+ */
+bool writeVst2State (const Vst2xState& state, Steinberg::IBStream& stream,
+ bool writeBypassState = true) noexcept;
+
+//------------------------------------------------------------------------
+/** Try loading the state from on old vst2 fxp format stream
+ *
+ * If successfully loaded, the program has either a chunk or plain values but not both
+ *
+ * @param stream the input stream
+ * @param vst2xUniqueID vst2 unique id expected to be stored in the stream
+ * @return on success the optional has a Vst2xProgram object with the data
+ */
+Optional tryVst2ProgramLoad (Steinberg::IBStream& stream,
+ Optional vst2xUniqueID) noexcept;
+
+//------------------------------------------------------------------------
+} // VST3
diff --git a/modules/juce_audio_processors/format_types/juce_VST3Headers.h b/modules/juce_audio_processors/format_types/juce_VST3Headers.h
index 2d757df6da..b8eb6dcddd 100644
--- a/modules/juce_audio_processors/format_types/juce_VST3Headers.h
+++ b/modules/juce_audio_processors/format_types/juce_VST3Headers.h
@@ -162,6 +162,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-W#warnings",
#pragma push_macro ("False")
#undef False
+ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wmultichar", "-Wfour-char-constants")
+
#include
#include
#include
@@ -176,6 +178,7 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-W#warnings",
#include
#include
#include
+ #include
#include
#include
#include
@@ -185,6 +188,8 @@ JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-W#warnings",
#include
#include
+ JUCE_END_IGNORE_WARNINGS_GCC_LIKE
+
#pragma pop_macro ("True")
#pragma pop_macro ("False")