cannam@233
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
cannam@233
|
2
|
cannam@233
|
3 /*
|
cannam@233
|
4 Vamp
|
cannam@233
|
5
|
cannam@233
|
6 An API for audio analysis and feature extraction plugins.
|
cannam@233
|
7
|
cannam@233
|
8 Centre for Digital Music, Queen Mary, University of London.
|
Chris@423
|
9 Copyright 2006-2016 Chris Cannam and QMUL.
|
cannam@233
|
10
|
cannam@233
|
11 Permission is hereby granted, free of charge, to any person
|
cannam@233
|
12 obtaining a copy of this software and associated documentation
|
cannam@233
|
13 files (the "Software"), to deal in the Software without
|
cannam@233
|
14 restriction, including without limitation the rights to use, copy,
|
cannam@233
|
15 modify, merge, publish, distribute, sublicense, and/or sell copies
|
cannam@233
|
16 of the Software, and to permit persons to whom the Software is
|
cannam@233
|
17 furnished to do so, subject to the following conditions:
|
cannam@233
|
18
|
cannam@233
|
19 The above copyright notice and this permission notice shall be
|
cannam@233
|
20 included in all copies or substantial portions of the Software.
|
cannam@233
|
21
|
cannam@233
|
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
cannam@233
|
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
cannam@233
|
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
cannam@233
|
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
|
cannam@233
|
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
cannam@233
|
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
cannam@233
|
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
cannam@233
|
29
|
cannam@233
|
30 Except as contained in this notice, the names of the Centre for
|
cannam@233
|
31 Digital Music; Queen Mary, University of London; and Chris Cannam
|
cannam@233
|
32 shall not be used in advertising or otherwise to promote the sale,
|
cannam@233
|
33 use or other dealings in this Software without prior written
|
cannam@233
|
34 authorization.
|
cannam@233
|
35 */
|
cannam@233
|
36
|
cannam@233
|
37 #include <vamp-hostsdk/PluginLoader.h>
|
cannam@233
|
38 #include <vamp-hostsdk/PluginInputDomainAdapter.h>
|
cannam@233
|
39 #include <vamp-hostsdk/PluginChannelAdapter.h>
|
cannam@233
|
40 #include <vamp-hostsdk/PluginBufferingAdapter.h>
|
Chris@390
|
41 #include <vamp-hostsdk/PluginHostAdapter.h>
|
Chris@390
|
42
|
Chris@390
|
43 #include <vamp/vamp.h>
|
Chris@390
|
44
|
Chris@390
|
45 #include "Files.h"
|
cannam@233
|
46
|
cannam@233
|
47 #include <fstream>
|
cannam@233
|
48
|
cannam@233
|
49 using namespace std;
|
cannam@233
|
50
|
cannam@263
|
51 _VAMP_SDK_HOSTSPACE_BEGIN(PluginLoader.cpp)
|
cannam@263
|
52
|
cannam@233
|
53 namespace Vamp {
|
cannam@233
|
54
|
cannam@233
|
55 namespace HostExt {
|
cannam@233
|
56
|
cannam@233
|
57 class PluginLoader::Impl
|
cannam@233
|
58 {
|
cannam@233
|
59 public:
|
cannam@233
|
60 Impl();
|
cannam@233
|
61 virtual ~Impl();
|
cannam@233
|
62
|
cannam@233
|
63 PluginKeyList listPlugins();
|
Chris@426
|
64 PluginStaticDataList listPluginData();
|
cannam@233
|
65
|
cannam@233
|
66 Plugin *loadPlugin(PluginKey key,
|
cannam@233
|
67 float inputSampleRate,
|
cannam@233
|
68 int adapterFlags);
|
cannam@233
|
69
|
Chris@423
|
70 LoadResponse loadPlugin(LoadRequest req);
|
Chris@423
|
71
|
Chris@431
|
72 ConfigurationResponse configurePlugin(ConfigurationRequest req);
|
Chris@423
|
73
|
cannam@233
|
74 PluginKey composePluginKey(string libraryName, string identifier);
|
cannam@233
|
75
|
cannam@233
|
76 PluginCategoryHierarchy getPluginCategory(PluginKey key);
|
cannam@233
|
77
|
cannam@233
|
78 string getLibraryPathForPlugin(PluginKey key);
|
cannam@233
|
79
|
cannam@233
|
80 static void setInstanceToClean(PluginLoader *instance);
|
cannam@233
|
81
|
cannam@233
|
82 protected:
|
cannam@233
|
83 class PluginDeletionNotifyAdapter : public PluginWrapper {
|
cannam@233
|
84 public:
|
cannam@233
|
85 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
|
cannam@233
|
86 virtual ~PluginDeletionNotifyAdapter();
|
cannam@233
|
87 protected:
|
cannam@233
|
88 Impl *m_loader;
|
cannam@233
|
89 };
|
cannam@233
|
90
|
cannam@233
|
91 class InstanceCleaner {
|
cannam@233
|
92 public:
|
cannam@233
|
93 InstanceCleaner() : m_instance(0) { }
|
cannam@233
|
94 ~InstanceCleaner() { delete m_instance; }
|
cannam@233
|
95 void setInstance(PluginLoader *instance) { m_instance = instance; }
|
cannam@233
|
96 protected:
|
cannam@233
|
97 PluginLoader *m_instance;
|
cannam@233
|
98 };
|
cannam@233
|
99
|
cannam@233
|
100 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
|
cannam@233
|
101
|
cannam@233
|
102 map<PluginKey, string> m_pluginLibraryNameMap;
|
cannam@233
|
103 bool m_allPluginsEnumerated;
|
cannam@233
|
104 void enumeratePlugins(PluginKey forPlugin = "");
|
cannam@233
|
105
|
cannam@233
|
106 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
|
cannam@233
|
107 void generateTaxonomy();
|
cannam@233
|
108
|
cannam@233
|
109 map<Plugin *, void *> m_pluginLibraryHandleMap;
|
cannam@233
|
110
|
cannam@233
|
111 bool decomposePluginKey(PluginKey key,
|
cannam@233
|
112 string &libraryName, string &identifier);
|
cannam@233
|
113
|
cannam@233
|
114 static InstanceCleaner m_cleaner;
|
cannam@233
|
115 };
|
cannam@233
|
116
|
cannam@233
|
117 PluginLoader *
|
cannam@233
|
118 PluginLoader::m_instance = 0;
|
cannam@233
|
119
|
cannam@233
|
120 PluginLoader::Impl::InstanceCleaner
|
cannam@233
|
121 PluginLoader::Impl::m_cleaner;
|
cannam@233
|
122
|
cannam@233
|
123 PluginLoader::PluginLoader()
|
cannam@233
|
124 {
|
cannam@233
|
125 m_impl = new Impl();
|
cannam@233
|
126 }
|
cannam@233
|
127
|
cannam@233
|
128 PluginLoader::~PluginLoader()
|
cannam@233
|
129 {
|
cannam@233
|
130 delete m_impl;
|
cannam@233
|
131 }
|
cannam@233
|
132
|
cannam@233
|
133 PluginLoader *
|
cannam@233
|
134 PluginLoader::getInstance()
|
cannam@233
|
135 {
|
cannam@233
|
136 if (!m_instance) {
|
cannam@233
|
137 // The cleaner doesn't own the instance, because we leave the
|
cannam@233
|
138 // instance pointer in the base class for binary backwards
|
cannam@233
|
139 // compatibility reasons and to avoid waste
|
cannam@233
|
140 m_instance = new PluginLoader();
|
cannam@233
|
141 Impl::setInstanceToClean(m_instance);
|
cannam@233
|
142 }
|
cannam@233
|
143 return m_instance;
|
cannam@233
|
144 }
|
cannam@233
|
145
|
Chris@426
|
146 PluginLoader::PluginKeyList
|
cannam@233
|
147 PluginLoader::listPlugins()
|
cannam@233
|
148 {
|
cannam@233
|
149 return m_impl->listPlugins();
|
cannam@233
|
150 }
|
cannam@233
|
151
|
Chris@426
|
152 PluginLoader::PluginStaticDataList
|
Chris@426
|
153 PluginLoader::listPluginData()
|
Chris@426
|
154 {
|
Chris@426
|
155 return m_impl->listPluginData();
|
Chris@426
|
156 }
|
Chris@426
|
157
|
cannam@233
|
158 Plugin *
|
cannam@233
|
159 PluginLoader::loadPlugin(PluginKey key,
|
cannam@233
|
160 float inputSampleRate,
|
cannam@233
|
161 int adapterFlags)
|
cannam@233
|
162 {
|
cannam@233
|
163 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
|
cannam@233
|
164 }
|
cannam@233
|
165
|
Chris@423
|
166 LoadResponse
|
Chris@423
|
167 PluginLoader::loadPlugin(LoadRequest req)
|
Chris@423
|
168 {
|
Chris@423
|
169 return m_impl->loadPlugin(req);
|
Chris@423
|
170 }
|
Chris@423
|
171
|
Chris@431
|
172 ConfigurationResponse
|
Chris@431
|
173 PluginLoader::configurePlugin(ConfigurationRequest req)
|
Chris@423
|
174 {
|
Chris@431
|
175 return m_impl->configurePlugin(req);
|
Chris@423
|
176 }
|
Chris@423
|
177
|
cannam@233
|
178 PluginLoader::PluginKey
|
cannam@233
|
179 PluginLoader::composePluginKey(string libraryName, string identifier)
|
cannam@233
|
180 {
|
cannam@233
|
181 return m_impl->composePluginKey(libraryName, identifier);
|
cannam@233
|
182 }
|
cannam@233
|
183
|
cannam@233
|
184 PluginLoader::PluginCategoryHierarchy
|
cannam@233
|
185 PluginLoader::getPluginCategory(PluginKey key)
|
cannam@233
|
186 {
|
cannam@233
|
187 return m_impl->getPluginCategory(key);
|
cannam@233
|
188 }
|
cannam@233
|
189
|
cannam@233
|
190 string
|
cannam@233
|
191 PluginLoader::getLibraryPathForPlugin(PluginKey key)
|
cannam@233
|
192 {
|
cannam@233
|
193 return m_impl->getLibraryPathForPlugin(key);
|
cannam@233
|
194 }
|
cannam@233
|
195
|
cannam@233
|
196 PluginLoader::Impl::Impl() :
|
cannam@233
|
197 m_allPluginsEnumerated(false)
|
cannam@233
|
198 {
|
cannam@233
|
199 }
|
cannam@233
|
200
|
cannam@233
|
201 PluginLoader::Impl::~Impl()
|
cannam@233
|
202 {
|
cannam@233
|
203 }
|
cannam@233
|
204
|
cannam@233
|
205 void
|
cannam@233
|
206 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
|
cannam@233
|
207 {
|
cannam@233
|
208 m_cleaner.setInstance(instance);
|
cannam@233
|
209 }
|
cannam@233
|
210
|
Chris@426
|
211 PluginLoader::PluginKeyList
|
cannam@233
|
212 PluginLoader::Impl::listPlugins()
|
cannam@233
|
213 {
|
cannam@233
|
214 if (!m_allPluginsEnumerated) enumeratePlugins();
|
cannam@233
|
215
|
cannam@233
|
216 vector<PluginKey> plugins;
|
cannam@233
|
217 for (map<PluginKey, string>::iterator mi = m_pluginLibraryNameMap.begin();
|
cannam@233
|
218 mi != m_pluginLibraryNameMap.end(); ++mi) {
|
cannam@233
|
219 plugins.push_back(mi->first);
|
cannam@233
|
220 }
|
cannam@233
|
221
|
cannam@233
|
222 return plugins;
|
cannam@233
|
223 }
|
cannam@233
|
224
|
Chris@426
|
225 PluginLoader::PluginStaticDataList
|
Chris@426
|
226 PluginLoader::Impl::listPluginData()
|
Chris@426
|
227 {
|
Chris@426
|
228 PluginKeyList keys = listPlugins();
|
Chris@426
|
229 PluginStaticDataList dataList;
|
Chris@426
|
230
|
Chris@426
|
231 for (PluginKeyList::const_iterator ki = keys.begin(); ki != keys.end(); ++ki) {
|
Chris@426
|
232 string key = *ki;
|
Chris@426
|
233 Plugin *p = loadPlugin(key, 44100, 0);
|
Chris@426
|
234 if (p) {
|
Chris@426
|
235 PluginCategoryHierarchy category = getPluginCategory(key);
|
Chris@426
|
236 dataList.push_back(PluginStaticData::fromPlugin(key, category, p));
|
Chris@426
|
237 }
|
Chris@426
|
238 delete p;
|
Chris@426
|
239 }
|
Chris@426
|
240
|
Chris@426
|
241 return dataList;
|
Chris@426
|
242 }
|
Chris@426
|
243
|
cannam@233
|
244 void
|
cannam@233
|
245 PluginLoader::Impl::enumeratePlugins(PluginKey forPlugin)
|
cannam@233
|
246 {
|
cannam@233
|
247 string libraryName, identifier;
|
Chris@390
|
248 vector<string> fullPaths;
|
Chris@390
|
249
|
cannam@233
|
250 if (forPlugin != "") {
|
cannam@233
|
251 if (!decomposePluginKey(forPlugin, libraryName, identifier)) {
|
cannam@233
|
252 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: Invalid plugin key \""
|
cannam@233
|
253 << forPlugin << "\" in enumerate" << std::endl;
|
cannam@233
|
254 return;
|
cannam@233
|
255 }
|
Chris@390
|
256 fullPaths = Files::listLibraryFilesMatching(libraryName);
|
Chris@390
|
257 } else {
|
Chris@390
|
258 fullPaths = Files::listLibraryFiles();
|
cannam@233
|
259 }
|
cannam@233
|
260
|
Chris@390
|
261 for (size_t i = 0; i < fullPaths.size(); ++i) {
|
cannam@233
|
262
|
Chris@390
|
263 string fullPath = fullPaths[i];
|
Chris@390
|
264 void *handle = Files::loadLibrary(fullPath);
|
Chris@390
|
265 if (!handle) continue;
|
cannam@233
|
266
|
Chris@390
|
267 VampGetPluginDescriptorFunction fn =
|
Chris@390
|
268 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
|
Chris@390
|
269 (handle, "vampGetPluginDescriptor");
|
cannam@233
|
270
|
Chris@390
|
271 if (!fn) {
|
Chris@390
|
272 if (forPlugin != "") {
|
Chris@390
|
273 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
|
cannam@295
|
274 << fullPath << "\"" << endl;
|
cannam@295
|
275 }
|
Chris@390
|
276 Files::unloadLibrary(handle);
|
Chris@390
|
277 continue;
|
Chris@390
|
278 }
|
cannam@233
|
279
|
Chris@390
|
280 int index = 0;
|
Chris@390
|
281 const VampPluginDescriptor *descriptor = 0;
|
Chris@390
|
282 bool found = false;
|
Chris@390
|
283
|
Chris@390
|
284 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
Chris@390
|
285 ++index;
|
Chris@390
|
286 if (identifier != "") {
|
Chris@390
|
287 if (descriptor->identifier != identifier) continue;
|
Chris@390
|
288 }
|
Chris@390
|
289 found = true;
|
Chris@390
|
290 PluginKey key = composePluginKey(fullPath, descriptor->identifier);
|
Chris@390
|
291 // std::cerr << "enumerate: " << key << " (path: " << fullPath << ")" << std::endl;
|
Chris@390
|
292 if (m_pluginLibraryNameMap.find(key) ==
|
Chris@390
|
293 m_pluginLibraryNameMap.end()) {
|
Chris@390
|
294 m_pluginLibraryNameMap[key] = fullPath;
|
Chris@390
|
295 }
|
cannam@233
|
296 }
|
Chris@390
|
297
|
Chris@390
|
298 if (!found && forPlugin != "") {
|
Chris@390
|
299 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
|
Chris@390
|
300 << identifier << "\" not found in library \""
|
Chris@390
|
301 << fullPath << "\"" << endl;
|
Chris@390
|
302 }
|
Chris@390
|
303
|
Chris@390
|
304 Files::unloadLibrary(handle);
|
cannam@233
|
305 }
|
cannam@233
|
306
|
cannam@233
|
307 if (forPlugin == "") m_allPluginsEnumerated = true;
|
cannam@233
|
308 }
|
cannam@233
|
309
|
cannam@233
|
310 PluginLoader::PluginKey
|
cannam@233
|
311 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
|
cannam@233
|
312 {
|
Chris@390
|
313 string basename = Files::lcBasename(libraryName);
|
cannam@233
|
314 return basename + ":" + identifier;
|
cannam@233
|
315 }
|
cannam@233
|
316
|
cannam@233
|
317 bool
|
cannam@233
|
318 PluginLoader::Impl::decomposePluginKey(PluginKey key,
|
cannam@233
|
319 string &libraryName,
|
cannam@233
|
320 string &identifier)
|
cannam@233
|
321 {
|
cannam@233
|
322 string::size_type ki = key.find(':');
|
cannam@233
|
323 if (ki == string::npos) {
|
cannam@233
|
324 return false;
|
cannam@233
|
325 }
|
cannam@233
|
326
|
cannam@233
|
327 libraryName = key.substr(0, ki);
|
cannam@233
|
328 identifier = key.substr(ki + 1);
|
cannam@233
|
329 return true;
|
cannam@233
|
330 }
|
cannam@233
|
331
|
cannam@233
|
332 PluginLoader::PluginCategoryHierarchy
|
cannam@233
|
333 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
|
cannam@233
|
334 {
|
cannam@233
|
335 if (m_taxonomy.empty()) generateTaxonomy();
|
cannam@233
|
336 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
|
cannam@233
|
337 return PluginCategoryHierarchy();
|
cannam@233
|
338 }
|
cannam@233
|
339 return m_taxonomy[plugin];
|
cannam@233
|
340 }
|
cannam@233
|
341
|
cannam@233
|
342 string
|
cannam@233
|
343 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
|
cannam@233
|
344 {
|
cannam@233
|
345 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
|
cannam@233
|
346 if (m_allPluginsEnumerated) return "";
|
cannam@233
|
347 enumeratePlugins(plugin);
|
cannam@233
|
348 }
|
cannam@233
|
349 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
|
cannam@233
|
350 return "";
|
cannam@233
|
351 }
|
cannam@233
|
352 return m_pluginLibraryNameMap[plugin];
|
cannam@233
|
353 }
|
cannam@233
|
354
|
cannam@233
|
355 Plugin *
|
cannam@233
|
356 PluginLoader::Impl::loadPlugin(PluginKey key,
|
cannam@233
|
357 float inputSampleRate, int adapterFlags)
|
cannam@233
|
358 {
|
cannam@233
|
359 string libname, identifier;
|
cannam@233
|
360 if (!decomposePluginKey(key, libname, identifier)) {
|
cannam@233
|
361 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
|
cannam@233
|
362 << key << "\" in loadPlugin" << std::endl;
|
cannam@233
|
363 return 0;
|
cannam@233
|
364 }
|
cannam@233
|
365
|
cannam@233
|
366 string fullPath = getLibraryPathForPlugin(key);
|
cannam@293
|
367 if (fullPath == "") {
|
cannam@295
|
368 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
|
cannam@293
|
369 return 0;
|
cannam@293
|
370 }
|
cannam@233
|
371
|
Chris@390
|
372 void *handle = Files::loadLibrary(fullPath);
|
cannam@233
|
373 if (!handle) return 0;
|
cannam@233
|
374
|
cannam@233
|
375 VampGetPluginDescriptorFunction fn =
|
Chris@390
|
376 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
|
cannam@233
|
377 (handle, "vampGetPluginDescriptor");
|
cannam@233
|
378
|
cannam@233
|
379 if (!fn) {
|
cannam@293
|
380 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
|
cannam@293
|
381 << fullPath << "\"" << endl;
|
Chris@390
|
382 Files::unloadLibrary(handle);
|
cannam@233
|
383 return 0;
|
cannam@233
|
384 }
|
cannam@233
|
385
|
cannam@233
|
386 int index = 0;
|
cannam@233
|
387 const VampPluginDescriptor *descriptor = 0;
|
cannam@233
|
388
|
cannam@233
|
389 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
cannam@233
|
390
|
cannam@233
|
391 if (string(descriptor->identifier) == identifier) {
|
cannam@233
|
392
|
cannam@233
|
393 Vamp::PluginHostAdapter *plugin =
|
cannam@233
|
394 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
|
cannam@233
|
395
|
cannam@233
|
396 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
|
cannam@233
|
397
|
cannam@233
|
398 m_pluginLibraryHandleMap[adapter] = handle;
|
cannam@233
|
399
|
cannam@233
|
400 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
|
cannam@233
|
401 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
|
cannam@233
|
402 adapter = new PluginInputDomainAdapter(adapter);
|
cannam@233
|
403 }
|
cannam@233
|
404 }
|
cannam@233
|
405
|
cannam@233
|
406 if (adapterFlags & ADAPT_BUFFER_SIZE) {
|
cannam@233
|
407 adapter = new PluginBufferingAdapter(adapter);
|
cannam@233
|
408 }
|
cannam@233
|
409
|
cannam@233
|
410 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
|
cannam@233
|
411 adapter = new PluginChannelAdapter(adapter);
|
cannam@233
|
412 }
|
cannam@233
|
413
|
cannam@233
|
414 return adapter;
|
cannam@233
|
415 }
|
cannam@233
|
416
|
cannam@233
|
417 ++index;
|
cannam@233
|
418 }
|
cannam@233
|
419
|
cannam@233
|
420 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
|
cannam@233
|
421 << identifier << "\" not found in library \""
|
cannam@233
|
422 << fullPath << "\"" << endl;
|
cannam@233
|
423
|
cannam@233
|
424 return 0;
|
cannam@233
|
425 }
|
cannam@233
|
426
|
Chris@423
|
427 LoadResponse
|
Chris@423
|
428 PluginLoader::Impl::loadPlugin(LoadRequest req)
|
Chris@423
|
429 {
|
Chris@423
|
430 Plugin *plugin = loadPlugin(req.pluginKey,
|
Chris@423
|
431 req.inputSampleRate,
|
Chris@423
|
432 req.adapterFlags);
|
Chris@423
|
433 LoadResponse response;
|
Chris@425
|
434 response.plugin = plugin;
|
Chris@423
|
435 if (!plugin) return response;
|
Chris@423
|
436
|
Chris@423
|
437 response.plugin = plugin;
|
Chris@423
|
438 response.staticData = PluginStaticData::fromPlugin
|
Chris@423
|
439 (req.pluginKey,
|
Chris@423
|
440 getPluginCategory(req.pluginKey),
|
Chris@423
|
441 plugin);
|
Chris@423
|
442
|
Chris@423
|
443 int defaultChannels = 0;
|
Chris@423
|
444 if (plugin->getMinChannelCount() == plugin->getMaxChannelCount()) {
|
Chris@423
|
445 defaultChannels = plugin->getMinChannelCount();
|
Chris@423
|
446 }
|
Chris@423
|
447
|
Chris@423
|
448 response.defaultConfiguration = PluginConfiguration::fromPlugin
|
Chris@423
|
449 (plugin,
|
Chris@423
|
450 defaultChannels,
|
Chris@423
|
451 plugin->getPreferredStepSize(),
|
Chris@423
|
452 plugin->getPreferredBlockSize());
|
Chris@423
|
453
|
Chris@423
|
454 return response;
|
Chris@423
|
455 }
|
Chris@423
|
456
|
Chris@431
|
457 ConfigurationResponse
|
Chris@431
|
458 PluginLoader::Impl::configurePlugin(ConfigurationRequest req)
|
Chris@423
|
459 {
|
Chris@423
|
460 for (PluginConfiguration::ParameterMap::const_iterator i =
|
Chris@431
|
461 req.configuration.parameterValues.begin();
|
Chris@431
|
462 i != req.configuration.parameterValues.end(); ++i) {
|
Chris@431
|
463 req.plugin->setParameter(i->first, i->second);
|
Chris@423
|
464 }
|
Chris@423
|
465
|
Chris@431
|
466 if (req.configuration.currentProgram != "") {
|
Chris@431
|
467 req.plugin->selectProgram(req.configuration.currentProgram);
|
Chris@423
|
468 }
|
Chris@423
|
469
|
Chris@431
|
470 ConfigurationResponse response;
|
Chris@431
|
471
|
Chris@455
|
472 response.plugin = req.plugin;
|
Chris@455
|
473
|
Chris@431
|
474 if (req.plugin->initialise(req.configuration.channelCount,
|
Chris@431
|
475 req.configuration.stepSize,
|
Chris@431
|
476 req.configuration.blockSize)) {
|
Chris@431
|
477 response.outputs = req.plugin->getOutputDescriptors();
|
Chris@423
|
478 }
|
Chris@431
|
479
|
Chris@431
|
480 return response;
|
Chris@423
|
481 }
|
Chris@423
|
482
|
cannam@233
|
483 void
|
cannam@233
|
484 PluginLoader::Impl::generateTaxonomy()
|
cannam@233
|
485 {
|
cannam@233
|
486 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
|
cannam@233
|
487
|
cannam@233
|
488 vector<string> path = PluginHostAdapter::getPluginPath();
|
cannam@233
|
489 string libfragment = "/lib/";
|
cannam@233
|
490 vector<string> catpath;
|
cannam@233
|
491
|
cannam@233
|
492 string suffix = "cat";
|
cannam@233
|
493
|
cannam@233
|
494 for (vector<string>::iterator i = path.begin();
|
cannam@233
|
495 i != path.end(); ++i) {
|
cannam@233
|
496
|
cannam@233
|
497 // It doesn't matter that we're using literal forward-slash in
|
cannam@233
|
498 // this bit, as it's only relevant if the path contains
|
cannam@233
|
499 // "/lib/", which is only meaningful and only plausible on
|
cannam@233
|
500 // systems with forward-slash delimiters
|
cannam@233
|
501
|
cannam@233
|
502 string dir = *i;
|
cannam@233
|
503 string::size_type li = dir.find(libfragment);
|
cannam@233
|
504
|
cannam@233
|
505 if (li != string::npos) {
|
cannam@233
|
506 catpath.push_back
|
cannam@233
|
507 (dir.substr(0, li)
|
cannam@233
|
508 + "/share/"
|
cannam@233
|
509 + dir.substr(li + libfragment.length()));
|
cannam@233
|
510 }
|
cannam@233
|
511
|
cannam@233
|
512 catpath.push_back(dir);
|
cannam@233
|
513 }
|
cannam@233
|
514
|
cannam@233
|
515 char buffer[1024];
|
cannam@233
|
516
|
cannam@233
|
517 for (vector<string>::iterator i = catpath.begin();
|
cannam@233
|
518 i != catpath.end(); ++i) {
|
cannam@233
|
519
|
Chris@390
|
520 vector<string> files = Files::listFiles(*i, suffix);
|
cannam@233
|
521
|
cannam@233
|
522 for (vector<string>::iterator fi = files.begin();
|
cannam@233
|
523 fi != files.end(); ++fi) {
|
cannam@233
|
524
|
Chris@390
|
525 string filepath = Files::splicePath(*i, *fi);
|
cannam@233
|
526 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
|
cannam@233
|
527
|
cannam@233
|
528 if (is.fail()) {
|
cannam@233
|
529 // cerr << "failed to open: " << filepath << endl;
|
cannam@233
|
530 continue;
|
cannam@233
|
531 }
|
cannam@233
|
532
|
cannam@233
|
533 // cerr << "opened: " << filepath << endl;
|
cannam@233
|
534
|
cannam@233
|
535 while (!!is.getline(buffer, 1024)) {
|
cannam@233
|
536
|
cannam@233
|
537 string line(buffer);
|
cannam@233
|
538
|
cannam@233
|
539 // cerr << "line = " << line << endl;
|
cannam@233
|
540
|
cannam@233
|
541 string::size_type di = line.find("::");
|
cannam@233
|
542 if (di == string::npos) continue;
|
cannam@233
|
543
|
cannam@233
|
544 string id = line.substr(0, di);
|
cannam@233
|
545 string encodedCat = line.substr(di + 2);
|
cannam@233
|
546
|
cannam@233
|
547 if (id.substr(0, 5) != "vamp:") continue;
|
cannam@233
|
548 id = id.substr(5);
|
cannam@233
|
549
|
cannam@233
|
550 while (encodedCat.length() >= 1 &&
|
cannam@233
|
551 encodedCat[encodedCat.length()-1] == '\r') {
|
cannam@233
|
552 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
|
cannam@233
|
553 }
|
cannam@233
|
554
|
cannam@233
|
555 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
|
cannam@233
|
556
|
cannam@233
|
557 PluginCategoryHierarchy category;
|
cannam@233
|
558 string::size_type ai;
|
cannam@233
|
559 while ((ai = encodedCat.find(" > ")) != string::npos) {
|
cannam@233
|
560 category.push_back(encodedCat.substr(0, ai));
|
cannam@233
|
561 encodedCat = encodedCat.substr(ai + 3);
|
cannam@233
|
562 }
|
cannam@233
|
563 if (encodedCat != "") category.push_back(encodedCat);
|
cannam@233
|
564
|
cannam@233
|
565 m_taxonomy[id] = category;
|
cannam@233
|
566 }
|
cannam@233
|
567 }
|
cannam@233
|
568 }
|
cannam@233
|
569 }
|
cannam@233
|
570
|
cannam@233
|
571 void
|
cannam@233
|
572 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
|
cannam@233
|
573 {
|
cannam@233
|
574 void *handle = m_pluginLibraryHandleMap[adapter];
|
Chris@390
|
575 if (handle) Files::unloadLibrary(handle);
|
cannam@233
|
576 m_pluginLibraryHandleMap.erase(adapter);
|
cannam@233
|
577 }
|
cannam@233
|
578
|
cannam@233
|
579 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
|
cannam@233
|
580 Impl *loader) :
|
cannam@233
|
581 PluginWrapper(plugin),
|
cannam@233
|
582 m_loader(loader)
|
cannam@233
|
583 {
|
cannam@233
|
584 }
|
cannam@233
|
585
|
cannam@233
|
586 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
|
cannam@233
|
587 {
|
cannam@233
|
588 // We need to delete the plugin before calling pluginDeleted, as
|
cannam@233
|
589 // the delete call may require calling through to the descriptor
|
cannam@233
|
590 // (for e.g. cleanup) but pluginDeleted may unload the required
|
cannam@233
|
591 // library for the call. To prevent a double deletion when our
|
cannam@233
|
592 // parent's destructor runs (after this one), be sure to set
|
cannam@233
|
593 // m_plugin to 0 after deletion.
|
cannam@233
|
594 delete m_plugin;
|
cannam@233
|
595 m_plugin = 0;
|
cannam@233
|
596
|
cannam@233
|
597 if (m_loader) m_loader->pluginDeleted(this);
|
cannam@233
|
598 }
|
cannam@233
|
599
|
cannam@233
|
600 }
|
cannam@233
|
601
|
cannam@233
|
602 }
|
cannam@263
|
603
|
cannam@263
|
604 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
|
cannam@263
|
605
|