RAM2118 commited on
Commit
4fe041d
·
verified ·
1 Parent(s): cf8bc89

Sprint 2: HostedPluginManager.cpp \u2014 load VST3/AU, enumerate params, route audio

Browse files
Files changed (1) hide show
  1. Source/HostedPluginManager.cpp +215 -7
Source/HostedPluginManager.cpp CHANGED
@@ -1,9 +1,217 @@
1
  #include "HostedPluginManager.h"
2
 
3
- // Phase 2: Full implementation with:
4
- // - loadPlugin(File, sampleRate, blockSize)
5
- // - unloadPlugin()
6
- // - searchParams(keyword)
7
- // - getParams(ids)
8
- // - setParams(values)
9
- // - Audio routing through hosted plugin
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #include "HostedPluginManager.h"
2
 
3
+ HostedPluginManager::HostedPluginManager()
4
+ {
5
+ // Register VST3 and AU formats
6
+ formatManager.addDefaultFormats();
7
+ }
8
+
9
+ HostedPluginManager::~HostedPluginManager()
10
+ {
11
+ unloadPlugin();
12
+ }
13
+
14
+ void HostedPluginManager::loadPlugin(const juce::File& pluginFile,
15
+ double sampleRate, int blockSize)
16
+ {
17
+ // Unload existing plugin first
18
+ unloadPlugin();
19
+
20
+ currentSampleRate = sampleRate;
21
+ currentBlockSize = blockSize;
22
+
23
+ juce::String errorMessage;
24
+ juce::OwnedArray<juce::PluginDescription> typesFound;
25
+
26
+ // Scan the file to find plugin descriptions
27
+ for (int i = 0; i < formatManager.getNumFormats(); ++i)
28
+ {
29
+ auto* format = formatManager.getFormat(i);
30
+ format->findAllTypesForFile(typesFound, pluginFile.getFullPathName());
31
+ if (typesFound.size() > 0)
32
+ break;
33
+ }
34
+
35
+ if (typesFound.isEmpty())
36
+ {
37
+ DBG("PluginBridge: No plugin found in file: " + pluginFile.getFullPathName());
38
+ return;
39
+ }
40
+
41
+ // Use the first plugin description found
42
+ auto& desc = *typesFound[0];
43
+
44
+ // Create plugin instance (synchronous — safe here since we're on message thread)
45
+ auto instance = formatManager.createPluginInstance(
46
+ desc, sampleRate, blockSize, errorMessage);
47
+
48
+ if (instance == nullptr)
49
+ {
50
+ DBG("PluginBridge: Failed to create plugin: " + errorMessage);
51
+ return;
52
+ }
53
+
54
+ // Enable all buses before use
55
+ instance->enableAllBuses();
56
+
57
+ // Match bus layout: stereo in/out
58
+ auto layout = juce::AudioProcessor::BusesLayout();
59
+ layout.inputBuses.add(juce::AudioChannelSet::stereo());
60
+ layout.outputBuses.add(juce::AudioChannelSet::stereo());
61
+
62
+ if (instance->checkBusesLayoutSupported(layout))
63
+ instance->setBusesLayout(layout);
64
+
65
+ // Prepare for playback
66
+ instance->prepareToPlay(sampleRate, blockSize);
67
+
68
+ // Store
69
+ {
70
+ const juce::ScopedLock sl(pluginLock);
71
+ hostedPlugin = std::move(instance);
72
+ loadedPluginPath = pluginFile.getFullPathName();
73
+ }
74
+
75
+ DBG("PluginBridge: Loaded plugin: " + getPluginName()
76
+ + " (" + juce::String(getParameterCount()) + " params)");
77
+ }
78
+
79
+ void HostedPluginManager::unloadPlugin()
80
+ {
81
+ const juce::ScopedLock sl(pluginLock);
82
+ if (hostedPlugin)
83
+ {
84
+ hostedPlugin->releaseResources();
85
+ hostedPlugin.reset();
86
+ loadedPluginPath.clear();
87
+ }
88
+ }
89
+
90
+ bool HostedPluginManager::isLoaded() const
91
+ {
92
+ return hostedPlugin != nullptr;
93
+ }
94
+
95
+ juce::String HostedPluginManager::getPluginName() const
96
+ {
97
+ if (hostedPlugin)
98
+ return hostedPlugin->getName();
99
+ return {};
100
+ }
101
+
102
+ void HostedPluginManager::prepareToPlay(double sampleRate, int blockSize)
103
+ {
104
+ currentSampleRate = sampleRate;
105
+ currentBlockSize = blockSize;
106
+
107
+ const juce::ScopedLock sl(pluginLock);
108
+ if (hostedPlugin)
109
+ hostedPlugin->prepareToPlay(sampleRate, blockSize);
110
+ }
111
+
112
+ void HostedPluginManager::processBlock(juce::AudioBuffer<float>& buffer, juce::MidiBuffer& midi)
113
+ {
114
+ const juce::ScopedLock sl(pluginLock);
115
+ if (hostedPlugin)
116
+ hostedPlugin->processBlock(buffer, midi);
117
+ }
118
+
119
+ void HostedPluginManager::releaseResources()
120
+ {
121
+ const juce::ScopedLock sl(pluginLock);
122
+ if (hostedPlugin)
123
+ hostedPlugin->releaseResources();
124
+ }
125
+
126
+ // --- Parameter Surface ---
127
+
128
+ int HostedPluginManager::getParameterCount() const
129
+ {
130
+ if (hostedPlugin)
131
+ return hostedPlugin->getParameters().size();
132
+ return 0;
133
+ }
134
+
135
+ std::vector<HostedPluginManager::ParamInfo> HostedPluginManager::searchParams(
136
+ const juce::String& keyword) const
137
+ {
138
+ std::vector<ParamInfo> results;
139
+ if (!hostedPlugin) return results;
140
+
141
+ auto& params = hostedPlugin->getParameters();
142
+ auto keywordLower = keyword.toLowerCase();
143
+
144
+ for (int i = 0; i < params.size(); ++i)
145
+ {
146
+ auto* param = params[i];
147
+ auto name = param->getName(128);
148
+
149
+ if (name.toLowerCase().contains(keywordLower))
150
+ {
151
+ ParamInfo info;
152
+ info.index = i;
153
+ info.name = name;
154
+ info.value = param->getValue();
155
+ info.displayText = param->getText(param->getValue(), 64);
156
+ info.automatable = param->isAutomatable();
157
+
158
+ // Try to get stable ID from HostedParameter
159
+ if (auto* hosted = dynamic_cast<juce::AudioPluginInstance::HostedParameter*>(param))
160
+ info.id = hosted->getParameterID();
161
+ else
162
+ info.id = juce::String(i);
163
+
164
+ results.push_back(info);
165
+ }
166
+
167
+ // Cap results to avoid token bloat
168
+ if (results.size() >= 20)
169
+ break;
170
+ }
171
+
172
+ return results;
173
+ }
174
+
175
+ std::vector<std::pair<int, float>> HostedPluginManager::getParams(
176
+ const std::vector<int>& indices) const
177
+ {
178
+ std::vector<std::pair<int, float>> results;
179
+ if (!hostedPlugin) return results;
180
+
181
+ auto& params = hostedPlugin->getParameters();
182
+
183
+ for (int idx : indices)
184
+ {
185
+ if (idx >= 0 && idx < params.size())
186
+ results.push_back({idx, params[idx]->getValue()});
187
+ }
188
+
189
+ return results;
190
+ }
191
+
192
+ bool HostedPluginManager::setParams(const std::map<int, float>& values)
193
+ {
194
+ if (!hostedPlugin) return false;
195
+
196
+ auto& params = hostedPlugin->getParameters();
197
+
198
+ for (auto& [idx, val] : values)
199
+ {
200
+ if (idx >= 0 && idx < params.size())
201
+ {
202
+ auto* param = params[idx];
203
+ float clampedVal = juce::jlimit(0.0f, 1.0f, val);
204
+
205
+ param->beginChangeGesture();
206
+ param->setValueNotifyingHost(clampedVal);
207
+ param->endChangeGesture();
208
+ }
209
+ }
210
+
211
+ return true;
212
+ }
213
+
214
+ juce::String HostedPluginManager::getLoadedPluginPath() const
215
+ {
216
+ return loadedPluginPath;
217
+ }