Skip to content

Commit d3b62da

Browse files
committed
Add syndicate plugin, enable juce7 vst3 hosting
Signed-off-by: falkTX <falktx@falktx.com>
1 parent af1ea64 commit d3b62da

File tree

258 files changed

+35383
-5
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

258 files changed

+35383
-5
lines changed

libs/juce7/AppConfig.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,7 @@
165165
166166
@see VSTPluginFormat, VST3PluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST, JUCE_PLUGINHOST_AU
167167
*/
168-
#if 0 //MAC || WINDOWS
169-
#define JUCE_PLUGINHOST_VST3 1
170-
#else
171-
#define JUCE_PLUGINHOST_VST3 0
172-
#endif
168+
#define JUCE_PLUGINHOST_VST3 1
173169

174170
/** Config: JUCE_PLUGINHOST_AU
175171
Enables the AudioUnit plugin hosting classes. This is Mac-only, of course.
@@ -188,6 +184,13 @@
188184
#define JUCE_PLUGINHOST_LADSPA 0
189185
#endif
190186

187+
/** Config: JUCE_PLUGINHOST_LV2
188+
* Enables the LV2 plugin hosting classes.
189+
*/
190+
#ifndef JUCE_PLUGINHOST_LV2
191+
#define JUCE_PLUGINHOST_LV2 0
192+
#endif
193+
191194
//=============================================================================
192195
// juce_audio_utils
193196

libs/juce7/meson.build

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ if linux_headless
55
'source/modules/juce_audio_basics/juce_audio_basics.cpp',
66
'source/modules/juce_audio_formats/juce_audio_formats.cpp',
77
'source/modules/juce_audio_processors/juce_audio_processors.cpp',
8+
# 'source/modules/juce_audio_processors/juce_audio_processors_lv2_libs.cpp',
89
'source/modules/juce_audio_utils/juce_audio_utils.cpp',
910
'source/modules/juce_core/juce_core.cpp',
1011
'source/modules/juce_cryptography/juce_cryptography.cpp',
@@ -17,6 +18,7 @@ else
1718
'source/modules/juce_audio_basics/juce_audio_basics.cpp',
1819
'source/modules/juce_audio_formats/juce_audio_formats.cpp',
1920
'source/modules/juce_audio_processors/juce_audio_processors.cpp',
21+
# 'source/modules/juce_audio_processors/juce_audio_processors_lv2_libs.cpp',
2022
'source/modules/juce_audio_utils/juce_audio_utils.cpp',
2123
'source/modules/juce_core/juce_core.cpp',
2224
'source/modules/juce_cryptography/juce_cryptography.cpp',
@@ -35,6 +37,7 @@ juce7_devices_srcs = [
3537
]
3638

3739
juce7_extra_cpp_args = [
40+
# '-DJUCE_PLUGINHOST_LV2=1',
3841
'-std=gnu++17',
3942
'-Wno-non-virtual-dtor',
4043
]
@@ -61,6 +64,14 @@ lib_juce7 = static_library('juce7',
6164
include_directories('.'),
6265
include_directories('source'),
6366
include_directories('source/modules'),
67+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK'),
68+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/serd'),
69+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/sord'),
70+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/sord/src'),
71+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/sratom'),
72+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/lilv'),
73+
# include_directories('source/modules/juce_audio_processors/format_types/LV2_SDK/lilv/src'),
74+
include_directories('source/modules/juce_audio_processors/format_types/VST3_SDK'),
6475
include_directories('../juced/source/dependancies/ladspa_sdk/src'),
6576
juce7_extra_include_dirs
6677
],

meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,10 @@ endif
366366
###############################################################################
367367
# extra files to install
368368

369+
if 'syndicate' in get_option('plugins')
370+
meson.add_install_script('scripts/install-syndicate-scanner.sh')
371+
endif
372+
369373
if 'tal-noisemaker' in get_option('plugins')
370374
extra_lv2_preset_files = [
371375
'TAL-NoiseMaker-Noise4U.lv2/manifest.ttl',

meson_options.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,5 +119,6 @@ option('plugins',
119119
'roth-air',
120120
'swankyamp',
121121
# juce7
122+
'syndicate',
122123
],
123124
)

ports-juce7/changes.patch

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
diff -U3 -r a/AllCommon/AllUtils.h b/AllCommon/AllUtils.h
2+
--- a/AllCommon/AllUtils.h 2025-09-15 00:11:06.845287312 +0200
3+
+++ b/AllCommon/AllUtils.h 2025-09-15 00:03:25.552521917 +0200
4+
@@ -10,23 +10,41 @@
5+
inline const char* SCAN_CONFIGURATION_FILE_NAME = "ScanConfiguration.txt";
6+
inline const char* CONFIG_FILE_NAME = "Config.json";
7+
8+
+ static inline juce::File getPluginScanServerBinary(juce::AudioProcessor::WrapperType wrapperType)
9+
+ {
10+
+ juce::File bin(juce::File::getSpecialLocation(juce::File::currentExecutableFile).getParentDirectory());
11+
+ switch (wrapperType)
12+
+ {
13+
+ case juce::AudioProcessor::wrapperType_LV2:
14+
+ break;
15+
+ case juce::AudioProcessor::wrapperType_VST:
16+
+ bin = bin.getChildFile("Resources");
17+
+ break;
18+
+ default:
19+
+ bin = bin.getSiblingFile("Resources");
20+
+ break;
21+
+ }
22+
+#if _WIN32
23+
+ return bin.getChildFile("PluginScanServer.exe");
24+
+#else
25+
+ return bin.getChildFile("PluginScanServer");
26+
+#endif
27+
+ }
28+
+
29+
#ifdef __APPLE__
30+
const juce::File DataDirectory(juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
31+
const juce::File PluginLogDirectory(juce::File::getSpecialLocation(juce::File::userHomeDirectory).getChildFile("Library/Logs/WhiteElephantAudio/Syndicate/Syndicate"));
32+
const juce::File PluginScanServerLogDirectory(juce::File::getSpecialLocation(juce::File::userHomeDirectory).getChildFile("Library/Logs/WhiteElephantAudio/Syndicate/PluginScanServer"));
33+
- const juce::File PluginScanServerBinary(juce::File::getSpecialLocation(juce::File::currentExecutableFile).getParentDirectory().getSiblingFile("Resources").getChildFile("PluginScanServer"));
34+
#elif _WIN32
35+
const juce::File ApplicationDirectory(juce::File::getSpecialLocation(juce::File::userDocumentsDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
36+
const juce::File DataDirectory(ApplicationDirectory.getChildFile("Data"));
37+
const juce::File PluginLogDirectory(ApplicationDirectory.getChildFile("Logs/Syndicate"));
38+
const juce::File PluginScanServerLogDirectory(ApplicationDirectory.getChildFile("Logs/PluginScanServer"));
39+
- const juce::File PluginScanServerBinary(juce::File::getSpecialLocation(juce::File::currentExecutableFile).getParentDirectory().getSiblingFile("Resources").getChildFile("PluginScanServer.exe"));
40+
#elif __linux__
41+
const juce::File ApplicationDirectory(juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
42+
const juce::File DataDirectory(ApplicationDirectory.getChildFile("Data"));
43+
const juce::File PluginLogDirectory(ApplicationDirectory.getChildFile("Logs/Syndicate"));
44+
const juce::File PluginScanServerLogDirectory(ApplicationDirectory.getChildFile("Logs/PluginScanServer"));
45+
- const juce::File PluginScanServerBinary(juce::File::getSpecialLocation(juce::File::currentExecutableFile).getParentDirectory().getSiblingFile("Resources").getChildFile("PluginScanServer"));
46+
#else
47+
#error Unsupported OS
48+
#endif
49+
diff -U3 -r a/PluginCommon/PluginScanning/CustomScanner.hpp b/PluginCommon/PluginScanning/CustomScanner.hpp
50+
--- a/PluginCommon/PluginScanning/CustomScanner.hpp 2025-09-15 00:11:06.845287312 +0200
51+
+++ b/PluginCommon/PluginScanning/CustomScanner.hpp 2025-09-15 00:07:31.353453853 +0200
52+
@@ -5,9 +5,9 @@
53+
54+
class Superprocess : private juce::ChildProcessCoordinator {
55+
public:
56+
- Superprocess() {
57+
+ Superprocess(juce::AudioProcessor::WrapperType wrapperType) {
58+
juce::Logger::writeToLog("Launching scan");
59+
- launchWorkerProcess(Utils::PluginScanServerBinary, Utils::PLUGIN_SCAN_SERVER_UID, 0, 0);
60+
+ launchWorkerProcess(Utils::getPluginScanServerBinary(wrapperType), Utils::PLUGIN_SCAN_SERVER_UID, 0, 0);
61+
}
62+
63+
enum class State {
64+
@@ -64,7 +64,8 @@
65+
66+
class CustomPluginScanner : public juce::KnownPluginList::CustomScanner {
67+
public:
68+
- CustomPluginScanner() { }
69+
+ CustomPluginScanner(juce::AudioProcessor::WrapperType wrapperType)
70+
+ : _wrapperType(wrapperType) { }
71+
72+
~CustomPluginScanner() override { }
73+
74+
@@ -95,7 +96,7 @@
75+
const juce::String& fileOrIdentifier,
76+
juce::OwnedArray<juce::PluginDescription>& result) {
77+
if (superprocess == nullptr) {
78+
- superprocess = std::make_unique<Superprocess>();
79+
+ superprocess = std::make_unique<Superprocess>(_wrapperType);
80+
}
81+
82+
juce::MemoryBlock block;
83+
@@ -132,6 +133,7 @@
84+
}
85+
}
86+
87+
+ const juce::AudioProcessor::WrapperType _wrapperType;
88+
std::unique_ptr<Superprocess> superprocess;
89+
90+
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomPluginScanner)
91+
diff -U3 -r a/PluginCommon/PluginScanning/PluginScanClient.cpp b/PluginCommon/PluginScanning/PluginScanClient.cpp
92+
--- a/PluginCommon/PluginScanning/PluginScanClient.cpp 2025-09-15 00:11:06.845287312 +0200
93+
+++ b/PluginCommon/PluginScanning/PluginScanClient.cpp 2025-09-15 00:08:49.852307156 +0200
94+
@@ -1,7 +1,8 @@
95+
#include "PluginScanClient.h"
96+
#include "CustomScanner.hpp"
97+
98+
-PluginScanClient::PluginScanClient() : juce::Thread("Scan Client"),
99+
+PluginScanClient::PluginScanClient(juce::AudioProcessor::WrapperType wrapperType) : juce::Thread("Scan Client"),
100+
+ _wrapperType(wrapperType),
101+
_hasAttemptedRestore(false),
102+
_shouldRestart(false),
103+
_shouldExit(false),
104+
@@ -18,7 +19,7 @@
105+
_hasAttemptedRestore = true;
106+
107+
_pluginList = std::make_unique<juce::KnownPluginList>();
108+
- _pluginList->setCustomScanner(std::make_unique<CustomPluginScanner>());
109+
+ _pluginList->setCustomScanner(std::make_unique<CustomPluginScanner>(_wrapperType));
110+
111+
const juce::File scannedPluginsFile(Utils::DataDirectory.getChildFile(Utils::SCANNED_PLUGINS_FILE_NAME));
112+
113+
@@ -61,7 +62,7 @@
114+
}
115+
116+
// Check the scanner binary exists
117+
- if (Utils::PluginScanServerBinary.existsAsFile()) {
118+
+ if (Utils::getPluginScanServerBinary(_wrapperType).existsAsFile()) {
119+
_errorMessage = "";
120+
} else {
121+
juce::Logger::writeToLog("PluginScanServer binary is missing");
122+
diff -U3 -r a/PluginCommon/PluginScanning/PluginScanClient.h b/PluginCommon/PluginScanning/PluginScanClient.h
123+
--- a/PluginCommon/PluginScanning/PluginScanClient.h 2025-09-15 00:11:06.845287312 +0200
124+
+++ b/PluginCommon/PluginScanning/PluginScanClient.h 2025-09-15 00:08:24.611389656 +0200
125+
@@ -17,7 +17,7 @@
126+
public:
127+
ScanConfiguration config;
128+
129+
- PluginScanClient();
130+
+ PluginScanClient(juce::AudioProcessor::WrapperType wrapperType);
131+
132+
juce::Array<juce::PluginDescription> getPluginTypes() const;
133+
134+
@@ -64,6 +64,7 @@
135+
void changeListenerCallback(juce::ChangeBroadcaster* changed) override;
136+
137+
private:
138+
+ const juce::AudioProcessor::WrapperType _wrapperType;
139+
std::unique_ptr<juce::KnownPluginList> _pluginList;
140+
juce::File _scannedPluginsFile;
141+
std::vector<juce::MessageListener*> _listeners;
142+
diff -U3 -r a/Syndicate/PluginProcessor.cpp b/Syndicate/PluginProcessor.cpp
143+
--- a/Syndicate/PluginProcessor.cpp 2025-09-15 00:11:06.849287455 +0200
144+
+++ b/Syndicate/PluginProcessor.cpp 2025-09-15 00:10:12.475310687 +0200
145+
@@ -57,6 +57,7 @@
146+
WECore::JUCEPlugin::CoreAudioProcessor(BusesProperties().withInput("Input", juce::AudioChannelSet::stereo(), true)
147+
.withOutput("Output", juce::AudioChannelSet::stereo(), true)
148+
.withInput("Sidechain", juce::AudioChannelSet::stereo(), true)),
149+
+ pluginScanClient(wrapperType),
150+
manager({getBusesLayout(), getSampleRate(), getBlockSize()},
151+
[&](int id, MODULATION_TYPE type) { return getModulationValueForSource(id, type); },
152+
[&](int newLatencySamples) { onLatencyChange(newLatencySamples); }),
153+
@@ -231,7 +232,7 @@
154+
buffer.clear (i, 0, buffer.getNumSamples());
155+
156+
// Send tempo and playhead information to the LFOs
157+
- juce::AudioPlayHead::CurrentPositionInfo mTempoInfo;
158+
+ juce::AudioPlayHead::CurrentPositionInfo mTempoInfo{};
159+
getPlayHead()->getCurrentPosition(mTempoInfo);
160+
161+
// Pass the audio through the splitter (this is also the only safe place to pass the playhead through)
162+
diff -U3 -r a/Syndicate/UI/ModulationBar/ModulationBar.cpp b/Syndicate/UI/ModulationBar/ModulationBar.cpp
163+
--- a/Syndicate/UI/ModulationBar/ModulationBar.cpp 2025-09-15 00:11:06.849287455 +0200
164+
+++ b/Syndicate/UI/ModulationBar/ModulationBar.cpp 2025-09-14 23:21:28.077252227 +0200
165+
@@ -355,6 +355,8 @@
166+
return _rndButtons[buttonIndex]->definition;
167+
}
168+
}
169+
+
170+
+ return selectedDefinition;
171+
}
172+
173+
void ModulationBar::_attemptToSelectByDefinition(ModulationSourceDefinition definition) {
174+
diff -U3 -r a/Syndicate/UI/UIUtils.cpp b/Syndicate/UI/UIUtils.cpp
175+
--- a/Syndicate/UI/UIUtils.cpp 2025-09-15 00:11:06.853287603 +0200
176+
+++ b/Syndicate/UI/UIUtils.cpp 2025-09-14 23:15:42.904133494 +0200
177+
@@ -189,7 +189,7 @@
178+
return lfoColour;
179+
case MODULATION_TYPE::ENVELOPE:
180+
return envelopeColour;
181+
- case MODULATION_TYPE::RANDOM:
182+
+ default:
183+
return randomColour;
184+
}
185+
}

ports-juce7/meson.build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ if linux_headless
55
]
66
else
77
plugins = [
8+
'syndicate'
89
]
910
endif
1011

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#pragma once
2+
3+
#include <JuceHeader.h>
4+
5+
namespace Utils {
6+
inline const char* PLUGIN_SCAN_SERVER_UID = "pluginScanServer";
7+
8+
inline const char* SCANNED_PLUGINS_FILE_NAME = "ScannedPlugins.txt";
9+
inline const char* CRASHED_PLUGINS_FILE_NAME = "CrashedPlugins.txt";
10+
inline const char* SCAN_CONFIGURATION_FILE_NAME = "ScanConfiguration.txt";
11+
inline const char* CONFIG_FILE_NAME = "Config.json";
12+
13+
static inline juce::File getPluginScanServerBinary(juce::AudioProcessor::WrapperType wrapperType)
14+
{
15+
juce::File bin(juce::File::getSpecialLocation(juce::File::currentExecutableFile).getParentDirectory());
16+
switch (wrapperType)
17+
{
18+
case juce::AudioProcessor::wrapperType_LV2:
19+
break;
20+
case juce::AudioProcessor::wrapperType_VST:
21+
bin = bin.getChildFile("Resources");
22+
break;
23+
default:
24+
bin = bin.getSiblingFile("Resources");
25+
break;
26+
}
27+
#if _WIN32
28+
return bin.getChildFile("PluginScanServer.exe");
29+
#else
30+
return bin.getChildFile("PluginScanServer");
31+
#endif
32+
}
33+
34+
#ifdef __APPLE__
35+
const juce::File DataDirectory(juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
36+
const juce::File PluginLogDirectory(juce::File::getSpecialLocation(juce::File::userHomeDirectory).getChildFile("Library/Logs/WhiteElephantAudio/Syndicate/Syndicate"));
37+
const juce::File PluginScanServerLogDirectory(juce::File::getSpecialLocation(juce::File::userHomeDirectory).getChildFile("Library/Logs/WhiteElephantAudio/Syndicate/PluginScanServer"));
38+
#elif _WIN32
39+
const juce::File ApplicationDirectory(juce::File::getSpecialLocation(juce::File::userDocumentsDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
40+
const juce::File DataDirectory(ApplicationDirectory.getChildFile("Data"));
41+
const juce::File PluginLogDirectory(ApplicationDirectory.getChildFile("Logs/Syndicate"));
42+
const juce::File PluginScanServerLogDirectory(ApplicationDirectory.getChildFile("Logs/PluginScanServer"));
43+
#elif __linux__
44+
const juce::File ApplicationDirectory(juce::File::getSpecialLocation(juce::File::userApplicationDataDirectory).getChildFile("WhiteElephantAudio/Syndicate"));
45+
const juce::File DataDirectory(ApplicationDirectory.getChildFile("Data"));
46+
const juce::File PluginLogDirectory(ApplicationDirectory.getChildFile("Logs/Syndicate"));
47+
const juce::File PluginScanServerLogDirectory(ApplicationDirectory.getChildFile("Logs/PluginScanServer"));
48+
#else
49+
#error Unsupported OS
50+
#endif
51+
52+
struct Config {
53+
bool enableLogFile;
54+
55+
Config() : enableLogFile(false) { }
56+
};
57+
58+
inline Config LoadConfig() {
59+
Config config;
60+
61+
juce::File configFile(DataDirectory.getChildFile(CONFIG_FILE_NAME));
62+
if (!configFile.exists()) {
63+
return config;
64+
}
65+
66+
juce::FileInputStream input(configFile);
67+
if (!input.openedOk()) {
68+
return config;
69+
}
70+
71+
const juce::var json = juce::JSON::parse(input.readEntireStreamAsString());
72+
if (!json.isObject()) {
73+
return config;
74+
}
75+
76+
if (json.hasProperty("enableLogFile")) {
77+
const juce::var& enableLogFile = json["enableLogFile"];
78+
if (enableLogFile.isBool()) {
79+
config.enableLogFile = enableLogFile;
80+
}
81+
}
82+
83+
return config;
84+
}
85+
}

0 commit comments

Comments
 (0)