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@473
|
64 PluginKeyList listPluginsIn(vector<string>);
|
Chris@473
|
65 PluginKeyList listPluginsNotIn(vector<string>);
|
Chris@456
|
66
|
cannam@233
|
67 Plugin *loadPlugin(PluginKey key,
|
cannam@233
|
68 float inputSampleRate,
|
cannam@233
|
69 int adapterFlags);
|
Chris@423
|
70
|
cannam@233
|
71 PluginKey composePluginKey(string libraryName, string identifier);
|
cannam@233
|
72
|
cannam@233
|
73 PluginCategoryHierarchy getPluginCategory(PluginKey key);
|
cannam@233
|
74
|
cannam@233
|
75 string getLibraryPathForPlugin(PluginKey key);
|
cannam@233
|
76
|
cannam@233
|
77 static void setInstanceToClean(PluginLoader *instance);
|
cannam@233
|
78
|
cannam@233
|
79 protected:
|
cannam@233
|
80 class PluginDeletionNotifyAdapter : public PluginWrapper {
|
cannam@233
|
81 public:
|
cannam@233
|
82 PluginDeletionNotifyAdapter(Plugin *plugin, Impl *loader);
|
cannam@233
|
83 virtual ~PluginDeletionNotifyAdapter();
|
cannam@233
|
84 protected:
|
cannam@233
|
85 Impl *m_loader;
|
cannam@233
|
86 };
|
cannam@233
|
87
|
cannam@233
|
88 class InstanceCleaner {
|
cannam@233
|
89 public:
|
cannam@233
|
90 InstanceCleaner() : m_instance(0) { }
|
cannam@233
|
91 ~InstanceCleaner() { delete m_instance; }
|
cannam@233
|
92 void setInstance(PluginLoader *instance) { m_instance = instance; }
|
cannam@233
|
93 protected:
|
cannam@233
|
94 PluginLoader *m_instance;
|
cannam@233
|
95 };
|
cannam@233
|
96
|
cannam@233
|
97 virtual void pluginDeleted(PluginDeletionNotifyAdapter *adapter);
|
cannam@233
|
98
|
cannam@233
|
99 map<PluginKey, string> m_pluginLibraryNameMap;
|
cannam@233
|
100 bool m_allPluginsEnumerated;
|
Chris@473
|
101
|
Chris@473
|
102 struct Enumeration {
|
Chris@473
|
103 enum { All, SinglePlugin, InLibraries, NotInLibraries } type;
|
Chris@473
|
104 PluginKey key;
|
Chris@473
|
105 vector<string> libraryNames;
|
Chris@473
|
106 Enumeration() : type(All) { }
|
Chris@473
|
107 };
|
Chris@473
|
108 vector<string> listLibraryFilesFor(Enumeration);
|
Chris@473
|
109
|
Chris@473
|
110 /// Populate m_pluginLibraryNameMap and return a list of the keys
|
Chris@473
|
111 /// that were added to it
|
Chris@473
|
112 vector<PluginKey> enumeratePlugins(Enumeration);
|
cannam@233
|
113
|
cannam@233
|
114 map<PluginKey, PluginCategoryHierarchy> m_taxonomy;
|
cannam@233
|
115 void generateTaxonomy();
|
cannam@233
|
116
|
cannam@233
|
117 map<Plugin *, void *> m_pluginLibraryHandleMap;
|
cannam@233
|
118
|
cannam@233
|
119 bool decomposePluginKey(PluginKey key,
|
cannam@233
|
120 string &libraryName, string &identifier);
|
cannam@233
|
121
|
cannam@233
|
122 static InstanceCleaner m_cleaner;
|
cannam@233
|
123 };
|
cannam@233
|
124
|
cannam@233
|
125 PluginLoader *
|
cannam@233
|
126 PluginLoader::m_instance = 0;
|
cannam@233
|
127
|
cannam@233
|
128 PluginLoader::Impl::InstanceCleaner
|
cannam@233
|
129 PluginLoader::Impl::m_cleaner;
|
cannam@233
|
130
|
cannam@233
|
131 PluginLoader::PluginLoader()
|
cannam@233
|
132 {
|
cannam@233
|
133 m_impl = new Impl();
|
cannam@233
|
134 }
|
cannam@233
|
135
|
cannam@233
|
136 PluginLoader::~PluginLoader()
|
cannam@233
|
137 {
|
cannam@233
|
138 delete m_impl;
|
cannam@233
|
139 }
|
cannam@233
|
140
|
cannam@233
|
141 PluginLoader *
|
cannam@233
|
142 PluginLoader::getInstance()
|
cannam@233
|
143 {
|
cannam@233
|
144 if (!m_instance) {
|
cannam@233
|
145 // The cleaner doesn't own the instance, because we leave the
|
cannam@233
|
146 // instance pointer in the base class for binary backwards
|
cannam@233
|
147 // compatibility reasons and to avoid waste
|
cannam@233
|
148 m_instance = new PluginLoader();
|
cannam@233
|
149 Impl::setInstanceToClean(m_instance);
|
cannam@233
|
150 }
|
cannam@233
|
151 return m_instance;
|
cannam@233
|
152 }
|
cannam@233
|
153
|
Chris@426
|
154 PluginLoader::PluginKeyList
|
cannam@233
|
155 PluginLoader::listPlugins()
|
cannam@233
|
156 {
|
cannam@233
|
157 return m_impl->listPlugins();
|
cannam@233
|
158 }
|
cannam@233
|
159
|
Chris@473
|
160 PluginLoader::PluginKeyList
|
Chris@473
|
161 PluginLoader::listPluginsIn(vector<string> libs)
|
Chris@473
|
162 {
|
Chris@473
|
163 return m_impl->listPluginsIn(libs);
|
Chris@473
|
164 }
|
Chris@473
|
165
|
Chris@473
|
166 PluginLoader::PluginKeyList
|
Chris@473
|
167 PluginLoader::listPluginsNotIn(vector<string> libs)
|
Chris@473
|
168 {
|
Chris@473
|
169 return m_impl->listPluginsNotIn(libs);
|
Chris@473
|
170 }
|
Chris@473
|
171
|
cannam@233
|
172 Plugin *
|
cannam@233
|
173 PluginLoader::loadPlugin(PluginKey key,
|
cannam@233
|
174 float inputSampleRate,
|
cannam@233
|
175 int adapterFlags)
|
cannam@233
|
176 {
|
cannam@233
|
177 return m_impl->loadPlugin(key, inputSampleRate, adapterFlags);
|
cannam@233
|
178 }
|
cannam@233
|
179
|
cannam@233
|
180 PluginLoader::PluginKey
|
cannam@233
|
181 PluginLoader::composePluginKey(string libraryName, string identifier)
|
cannam@233
|
182 {
|
cannam@233
|
183 return m_impl->composePluginKey(libraryName, identifier);
|
cannam@233
|
184 }
|
cannam@233
|
185
|
cannam@233
|
186 PluginLoader::PluginCategoryHierarchy
|
cannam@233
|
187 PluginLoader::getPluginCategory(PluginKey key)
|
cannam@233
|
188 {
|
cannam@233
|
189 return m_impl->getPluginCategory(key);
|
cannam@233
|
190 }
|
cannam@233
|
191
|
cannam@233
|
192 string
|
cannam@233
|
193 PluginLoader::getLibraryPathForPlugin(PluginKey key)
|
cannam@233
|
194 {
|
cannam@233
|
195 return m_impl->getLibraryPathForPlugin(key);
|
cannam@233
|
196 }
|
cannam@233
|
197
|
cannam@233
|
198 PluginLoader::Impl::Impl() :
|
cannam@233
|
199 m_allPluginsEnumerated(false)
|
cannam@233
|
200 {
|
cannam@233
|
201 }
|
cannam@233
|
202
|
cannam@233
|
203 PluginLoader::Impl::~Impl()
|
cannam@233
|
204 {
|
cannam@233
|
205 }
|
cannam@233
|
206
|
cannam@233
|
207 void
|
cannam@233
|
208 PluginLoader::Impl::setInstanceToClean(PluginLoader *instance)
|
cannam@233
|
209 {
|
cannam@233
|
210 m_cleaner.setInstance(instance);
|
cannam@233
|
211 }
|
cannam@233
|
212
|
Chris@426
|
213 PluginLoader::PluginKeyList
|
cannam@233
|
214 PluginLoader::Impl::listPlugins()
|
cannam@233
|
215 {
|
Chris@477
|
216 if (!m_allPluginsEnumerated) enumeratePlugins(Enumeration());
|
cannam@233
|
217
|
cannam@233
|
218 vector<PluginKey> plugins;
|
Chris@477
|
219 for (map<PluginKey, string>::const_iterator i =
|
Chris@477
|
220 m_pluginLibraryNameMap.begin();
|
Chris@477
|
221 i != m_pluginLibraryNameMap.end(); ++i) {
|
Chris@477
|
222 plugins.push_back(i->first);
|
cannam@233
|
223 }
|
cannam@233
|
224
|
cannam@233
|
225 return plugins;
|
cannam@233
|
226 }
|
cannam@233
|
227
|
Chris@473
|
228 PluginLoader::PluginKeyList
|
Chris@473
|
229 PluginLoader::Impl::listPluginsIn(vector<string> libs)
|
Chris@473
|
230 {
|
Chris@473
|
231 Enumeration enumeration;
|
Chris@473
|
232 enumeration.type = Enumeration::InLibraries;
|
Chris@473
|
233 enumeration.libraryNames = libs;
|
Chris@473
|
234 return enumeratePlugins(enumeration);
|
Chris@473
|
235 }
|
Chris@473
|
236
|
Chris@473
|
237 PluginLoader::PluginKeyList
|
Chris@473
|
238 PluginLoader::Impl::listPluginsNotIn(vector<string> libs)
|
Chris@473
|
239 {
|
Chris@473
|
240 Enumeration enumeration;
|
Chris@473
|
241 enumeration.type = Enumeration::NotInLibraries;
|
Chris@473
|
242 enumeration.libraryNames = libs;
|
Chris@473
|
243 return enumeratePlugins(enumeration);
|
Chris@473
|
244 }
|
Chris@473
|
245
|
Chris@473
|
246 vector<string>
|
Chris@473
|
247 PluginLoader::Impl::listLibraryFilesFor(Enumeration enumeration)
|
Chris@473
|
248 {
|
Chris@473
|
249 Files::Filter filter;
|
Chris@473
|
250
|
Chris@473
|
251 switch (enumeration.type) {
|
Chris@473
|
252
|
Chris@473
|
253 case Enumeration::All:
|
Chris@473
|
254 filter.type = Files::Filter::All;
|
Chris@473
|
255 break;
|
Chris@473
|
256
|
Chris@473
|
257 case Enumeration::SinglePlugin:
|
Chris@473
|
258 {
|
Chris@473
|
259 string libraryName, identifier;
|
Chris@473
|
260 if (!decomposePluginKey(enumeration.key, libraryName, identifier)) {
|
Chris@473
|
261 std::cerr << "WARNING: Vamp::HostExt::PluginLoader: "
|
Chris@473
|
262 << "Invalid plugin key \"" << enumeration.key
|
Chris@473
|
263 << "\" in enumerate" << std::endl;
|
Chris@477
|
264 return vector<string>();
|
Chris@473
|
265 }
|
Chris@473
|
266 filter.type = Files::Filter::Matching;
|
Chris@477
|
267 filter.libraryNames.clear();
|
Chris@477
|
268 filter.libraryNames.push_back(libraryName);
|
Chris@473
|
269 break;
|
Chris@473
|
270 }
|
Chris@473
|
271
|
Chris@473
|
272 case Enumeration::InLibraries:
|
Chris@473
|
273 filter.type = Files::Filter::Matching;
|
Chris@473
|
274 filter.libraryNames = enumeration.libraryNames;
|
Chris@473
|
275 break;
|
Chris@473
|
276
|
Chris@473
|
277 case Enumeration::NotInLibraries:
|
Chris@473
|
278 filter.type = Files::Filter::NotMatching;
|
Chris@473
|
279 filter.libraryNames = enumeration.libraryNames;
|
Chris@473
|
280 break;
|
Chris@473
|
281 }
|
Chris@473
|
282
|
Chris@473
|
283 return Files::listLibraryFilesMatching(filter);
|
Chris@473
|
284 }
|
Chris@473
|
285
|
Chris@473
|
286 vector<PluginLoader::PluginKey>
|
Chris@473
|
287 PluginLoader::Impl::enumeratePlugins(Enumeration enumeration)
|
cannam@233
|
288 {
|
cannam@233
|
289 string libraryName, identifier;
|
Chris@473
|
290 if (enumeration.type == Enumeration::SinglePlugin) {
|
Chris@473
|
291 decomposePluginKey(enumeration.key, libraryName, identifier);
|
Chris@473
|
292 }
|
Chris@390
|
293
|
Chris@473
|
294 vector<string> fullPaths = listLibraryFilesFor(enumeration);
|
cannam@233
|
295
|
Chris@473
|
296 // For these we should warn if a plugin can be loaded from a library
|
Chris@473
|
297 bool specific = (enumeration.type == Enumeration::SinglePlugin ||
|
Chris@473
|
298 enumeration.type == Enumeration::InLibraries);
|
Chris@473
|
299
|
Chris@473
|
300 vector<PluginKey> added;
|
Chris@473
|
301
|
Chris@390
|
302 for (size_t i = 0; i < fullPaths.size(); ++i) {
|
cannam@233
|
303
|
Chris@390
|
304 string fullPath = fullPaths[i];
|
Chris@390
|
305 void *handle = Files::loadLibrary(fullPath);
|
Chris@390
|
306 if (!handle) continue;
|
cannam@233
|
307
|
Chris@390
|
308 VampGetPluginDescriptorFunction fn =
|
Chris@390
|
309 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
|
Chris@390
|
310 (handle, "vampGetPluginDescriptor");
|
cannam@233
|
311
|
Chris@390
|
312 if (!fn) {
|
Chris@473
|
313 if (specific) {
|
Chris@473
|
314 cerr << "Vamp::HostExt::PluginLoader: "
|
Chris@473
|
315 << "No vampGetPluginDescriptor function found in library \""
|
cannam@295
|
316 << fullPath << "\"" << endl;
|
cannam@295
|
317 }
|
Chris@390
|
318 Files::unloadLibrary(handle);
|
Chris@390
|
319 continue;
|
Chris@390
|
320 }
|
cannam@233
|
321
|
Chris@390
|
322 int index = 0;
|
Chris@390
|
323 const VampPluginDescriptor *descriptor = 0;
|
Chris@390
|
324 bool found = false;
|
Chris@390
|
325
|
Chris@390
|
326 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
Chris@390
|
327 ++index;
|
Chris@390
|
328 if (identifier != "") {
|
Chris@473
|
329 if (descriptor->identifier != identifier) {
|
Chris@473
|
330 continue;
|
Chris@473
|
331 }
|
Chris@390
|
332 }
|
Chris@390
|
333 found = true;
|
Chris@390
|
334 PluginKey key = composePluginKey(fullPath, descriptor->identifier);
|
Chris@390
|
335 if (m_pluginLibraryNameMap.find(key) ==
|
Chris@390
|
336 m_pluginLibraryNameMap.end()) {
|
Chris@390
|
337 m_pluginLibraryNameMap[key] = fullPath;
|
Chris@390
|
338 }
|
Chris@473
|
339 added.push_back(key);
|
cannam@233
|
340 }
|
Chris@390
|
341
|
Chris@473
|
342 if (!found && specific) {
|
Chris@390
|
343 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
|
Chris@390
|
344 << identifier << "\" not found in library \""
|
Chris@390
|
345 << fullPath << "\"" << endl;
|
Chris@390
|
346 }
|
Chris@390
|
347
|
Chris@390
|
348 Files::unloadLibrary(handle);
|
cannam@233
|
349 }
|
cannam@233
|
350
|
Chris@473
|
351 if (enumeration.type == Enumeration::All) {
|
Chris@473
|
352 m_allPluginsEnumerated = true;
|
Chris@473
|
353 }
|
Chris@473
|
354
|
Chris@473
|
355 return added;
|
cannam@233
|
356 }
|
cannam@233
|
357
|
cannam@233
|
358 PluginLoader::PluginKey
|
cannam@233
|
359 PluginLoader::Impl::composePluginKey(string libraryName, string identifier)
|
cannam@233
|
360 {
|
Chris@390
|
361 string basename = Files::lcBasename(libraryName);
|
cannam@233
|
362 return basename + ":" + identifier;
|
cannam@233
|
363 }
|
cannam@233
|
364
|
cannam@233
|
365 bool
|
cannam@233
|
366 PluginLoader::Impl::decomposePluginKey(PluginKey key,
|
cannam@233
|
367 string &libraryName,
|
cannam@233
|
368 string &identifier)
|
cannam@233
|
369 {
|
cannam@233
|
370 string::size_type ki = key.find(':');
|
cannam@233
|
371 if (ki == string::npos) {
|
cannam@233
|
372 return false;
|
cannam@233
|
373 }
|
cannam@233
|
374
|
cannam@233
|
375 libraryName = key.substr(0, ki);
|
cannam@233
|
376 identifier = key.substr(ki + 1);
|
cannam@233
|
377 return true;
|
cannam@233
|
378 }
|
cannam@233
|
379
|
cannam@233
|
380 PluginLoader::PluginCategoryHierarchy
|
cannam@233
|
381 PluginLoader::Impl::getPluginCategory(PluginKey plugin)
|
cannam@233
|
382 {
|
cannam@233
|
383 if (m_taxonomy.empty()) generateTaxonomy();
|
cannam@233
|
384 if (m_taxonomy.find(plugin) == m_taxonomy.end()) {
|
cannam@233
|
385 return PluginCategoryHierarchy();
|
cannam@233
|
386 }
|
cannam@233
|
387 return m_taxonomy[plugin];
|
cannam@233
|
388 }
|
cannam@233
|
389
|
cannam@233
|
390 string
|
cannam@233
|
391 PluginLoader::Impl::getLibraryPathForPlugin(PluginKey plugin)
|
cannam@233
|
392 {
|
cannam@233
|
393 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
|
cannam@233
|
394 if (m_allPluginsEnumerated) return "";
|
Chris@473
|
395 Enumeration enumeration;
|
Chris@473
|
396 enumeration.type = Enumeration::SinglePlugin;
|
Chris@473
|
397 enumeration.key = plugin;
|
Chris@473
|
398 enumeratePlugins(enumeration);
|
cannam@233
|
399 }
|
cannam@233
|
400 if (m_pluginLibraryNameMap.find(plugin) == m_pluginLibraryNameMap.end()) {
|
cannam@233
|
401 return "";
|
cannam@233
|
402 }
|
cannam@233
|
403 return m_pluginLibraryNameMap[plugin];
|
cannam@233
|
404 }
|
cannam@233
|
405
|
cannam@233
|
406 Plugin *
|
cannam@233
|
407 PluginLoader::Impl::loadPlugin(PluginKey key,
|
cannam@233
|
408 float inputSampleRate, int adapterFlags)
|
cannam@233
|
409 {
|
cannam@233
|
410 string libname, identifier;
|
cannam@233
|
411 if (!decomposePluginKey(key, libname, identifier)) {
|
cannam@233
|
412 std::cerr << "Vamp::HostExt::PluginLoader: Invalid plugin key \""
|
cannam@233
|
413 << key << "\" in loadPlugin" << std::endl;
|
cannam@233
|
414 return 0;
|
cannam@233
|
415 }
|
cannam@233
|
416
|
cannam@233
|
417 string fullPath = getLibraryPathForPlugin(key);
|
cannam@293
|
418 if (fullPath == "") {
|
cannam@295
|
419 std::cerr << "Vamp::HostExt::PluginLoader: No library found in Vamp path for plugin \"" << key << "\"" << std::endl;
|
cannam@293
|
420 return 0;
|
cannam@293
|
421 }
|
cannam@233
|
422
|
Chris@390
|
423 void *handle = Files::loadLibrary(fullPath);
|
cannam@233
|
424 if (!handle) return 0;
|
cannam@233
|
425
|
cannam@233
|
426 VampGetPluginDescriptorFunction fn =
|
Chris@390
|
427 (VampGetPluginDescriptorFunction)Files::lookupInLibrary
|
cannam@233
|
428 (handle, "vampGetPluginDescriptor");
|
cannam@233
|
429
|
cannam@233
|
430 if (!fn) {
|
cannam@293
|
431 cerr << "Vamp::HostExt::PluginLoader: No vampGetPluginDescriptor function found in library \""
|
cannam@293
|
432 << fullPath << "\"" << endl;
|
Chris@390
|
433 Files::unloadLibrary(handle);
|
cannam@233
|
434 return 0;
|
cannam@233
|
435 }
|
cannam@233
|
436
|
cannam@233
|
437 int index = 0;
|
cannam@233
|
438 const VampPluginDescriptor *descriptor = 0;
|
cannam@233
|
439
|
cannam@233
|
440 while ((descriptor = fn(VAMP_API_VERSION, index))) {
|
cannam@233
|
441
|
cannam@233
|
442 if (string(descriptor->identifier) == identifier) {
|
cannam@233
|
443
|
cannam@233
|
444 Vamp::PluginHostAdapter *plugin =
|
cannam@233
|
445 new Vamp::PluginHostAdapter(descriptor, inputSampleRate);
|
cannam@233
|
446
|
cannam@233
|
447 Plugin *adapter = new PluginDeletionNotifyAdapter(plugin, this);
|
cannam@233
|
448
|
cannam@233
|
449 m_pluginLibraryHandleMap[adapter] = handle;
|
cannam@233
|
450
|
cannam@233
|
451 if (adapterFlags & ADAPT_INPUT_DOMAIN) {
|
cannam@233
|
452 if (adapter->getInputDomain() == Plugin::FrequencyDomain) {
|
cannam@233
|
453 adapter = new PluginInputDomainAdapter(adapter);
|
cannam@233
|
454 }
|
cannam@233
|
455 }
|
cannam@233
|
456
|
cannam@233
|
457 if (adapterFlags & ADAPT_BUFFER_SIZE) {
|
cannam@233
|
458 adapter = new PluginBufferingAdapter(adapter);
|
cannam@233
|
459 }
|
cannam@233
|
460
|
cannam@233
|
461 if (adapterFlags & ADAPT_CHANNEL_COUNT) {
|
cannam@233
|
462 adapter = new PluginChannelAdapter(adapter);
|
cannam@233
|
463 }
|
cannam@233
|
464
|
cannam@233
|
465 return adapter;
|
cannam@233
|
466 }
|
cannam@233
|
467
|
cannam@233
|
468 ++index;
|
cannam@233
|
469 }
|
cannam@233
|
470
|
cannam@233
|
471 cerr << "Vamp::HostExt::PluginLoader: Plugin \""
|
cannam@233
|
472 << identifier << "\" not found in library \""
|
cannam@233
|
473 << fullPath << "\"" << endl;
|
cannam@233
|
474
|
cannam@233
|
475 return 0;
|
cannam@233
|
476 }
|
cannam@233
|
477
|
cannam@233
|
478 void
|
cannam@233
|
479 PluginLoader::Impl::generateTaxonomy()
|
cannam@233
|
480 {
|
cannam@233
|
481 // cerr << "PluginLoader::Impl::generateTaxonomy" << endl;
|
cannam@233
|
482
|
cannam@233
|
483 vector<string> path = PluginHostAdapter::getPluginPath();
|
cannam@233
|
484 string libfragment = "/lib/";
|
cannam@233
|
485 vector<string> catpath;
|
cannam@233
|
486
|
cannam@233
|
487 string suffix = "cat";
|
cannam@233
|
488
|
cannam@233
|
489 for (vector<string>::iterator i = path.begin();
|
cannam@233
|
490 i != path.end(); ++i) {
|
cannam@233
|
491
|
cannam@233
|
492 // It doesn't matter that we're using literal forward-slash in
|
cannam@233
|
493 // this bit, as it's only relevant if the path contains
|
cannam@233
|
494 // "/lib/", which is only meaningful and only plausible on
|
cannam@233
|
495 // systems with forward-slash delimiters
|
cannam@233
|
496
|
cannam@233
|
497 string dir = *i;
|
cannam@233
|
498 string::size_type li = dir.find(libfragment);
|
cannam@233
|
499
|
cannam@233
|
500 if (li != string::npos) {
|
cannam@233
|
501 catpath.push_back
|
cannam@233
|
502 (dir.substr(0, li)
|
cannam@233
|
503 + "/share/"
|
cannam@233
|
504 + dir.substr(li + libfragment.length()));
|
cannam@233
|
505 }
|
cannam@233
|
506
|
cannam@233
|
507 catpath.push_back(dir);
|
cannam@233
|
508 }
|
cannam@233
|
509
|
cannam@233
|
510 char buffer[1024];
|
cannam@233
|
511
|
cannam@233
|
512 for (vector<string>::iterator i = catpath.begin();
|
cannam@233
|
513 i != catpath.end(); ++i) {
|
cannam@233
|
514
|
Chris@390
|
515 vector<string> files = Files::listFiles(*i, suffix);
|
cannam@233
|
516
|
cannam@233
|
517 for (vector<string>::iterator fi = files.begin();
|
cannam@233
|
518 fi != files.end(); ++fi) {
|
cannam@233
|
519
|
Chris@390
|
520 string filepath = Files::splicePath(*i, *fi);
|
cannam@233
|
521 ifstream is(filepath.c_str(), ifstream::in | ifstream::binary);
|
cannam@233
|
522
|
cannam@233
|
523 if (is.fail()) {
|
cannam@233
|
524 // cerr << "failed to open: " << filepath << endl;
|
cannam@233
|
525 continue;
|
cannam@233
|
526 }
|
cannam@233
|
527
|
cannam@233
|
528 // cerr << "opened: " << filepath << endl;
|
cannam@233
|
529
|
cannam@233
|
530 while (!!is.getline(buffer, 1024)) {
|
cannam@233
|
531
|
cannam@233
|
532 string line(buffer);
|
cannam@233
|
533
|
cannam@233
|
534 // cerr << "line = " << line << endl;
|
cannam@233
|
535
|
cannam@233
|
536 string::size_type di = line.find("::");
|
cannam@233
|
537 if (di == string::npos) continue;
|
cannam@233
|
538
|
cannam@233
|
539 string id = line.substr(0, di);
|
cannam@233
|
540 string encodedCat = line.substr(di + 2);
|
cannam@233
|
541
|
cannam@233
|
542 if (id.substr(0, 5) != "vamp:") continue;
|
cannam@233
|
543 id = id.substr(5);
|
cannam@233
|
544
|
cannam@233
|
545 while (encodedCat.length() >= 1 &&
|
cannam@233
|
546 encodedCat[encodedCat.length()-1] == '\r') {
|
cannam@233
|
547 encodedCat = encodedCat.substr(0, encodedCat.length()-1);
|
cannam@233
|
548 }
|
cannam@233
|
549
|
cannam@233
|
550 // cerr << "id = " << id << ", cat = " << encodedCat << endl;
|
cannam@233
|
551
|
cannam@233
|
552 PluginCategoryHierarchy category;
|
cannam@233
|
553 string::size_type ai;
|
cannam@233
|
554 while ((ai = encodedCat.find(" > ")) != string::npos) {
|
cannam@233
|
555 category.push_back(encodedCat.substr(0, ai));
|
cannam@233
|
556 encodedCat = encodedCat.substr(ai + 3);
|
cannam@233
|
557 }
|
cannam@233
|
558 if (encodedCat != "") category.push_back(encodedCat);
|
cannam@233
|
559
|
cannam@233
|
560 m_taxonomy[id] = category;
|
cannam@233
|
561 }
|
cannam@233
|
562 }
|
cannam@233
|
563 }
|
cannam@233
|
564 }
|
cannam@233
|
565
|
cannam@233
|
566 void
|
cannam@233
|
567 PluginLoader::Impl::pluginDeleted(PluginDeletionNotifyAdapter *adapter)
|
cannam@233
|
568 {
|
cannam@233
|
569 void *handle = m_pluginLibraryHandleMap[adapter];
|
Chris@524
|
570 if (!handle) return;
|
Chris@524
|
571
|
cannam@233
|
572 m_pluginLibraryHandleMap.erase(adapter);
|
Chris@524
|
573
|
Chris@524
|
574 for (auto h: m_pluginLibraryHandleMap) {
|
Chris@524
|
575 if (h.second == handle) {
|
Chris@524
|
576 // still in use
|
Chris@524
|
577 return;
|
Chris@524
|
578 }
|
Chris@524
|
579 }
|
Chris@524
|
580
|
Chris@524
|
581 Files::unloadLibrary(handle);
|
cannam@233
|
582 }
|
cannam@233
|
583
|
cannam@233
|
584 PluginLoader::Impl::PluginDeletionNotifyAdapter::PluginDeletionNotifyAdapter(Plugin *plugin,
|
cannam@233
|
585 Impl *loader) :
|
cannam@233
|
586 PluginWrapper(plugin),
|
cannam@233
|
587 m_loader(loader)
|
cannam@233
|
588 {
|
cannam@233
|
589 }
|
cannam@233
|
590
|
cannam@233
|
591 PluginLoader::Impl::PluginDeletionNotifyAdapter::~PluginDeletionNotifyAdapter()
|
cannam@233
|
592 {
|
cannam@233
|
593 // We need to delete the plugin before calling pluginDeleted, as
|
cannam@233
|
594 // the delete call may require calling through to the descriptor
|
cannam@233
|
595 // (for e.g. cleanup) but pluginDeleted may unload the required
|
cannam@233
|
596 // library for the call. To prevent a double deletion when our
|
cannam@233
|
597 // parent's destructor runs (after this one), be sure to set
|
cannam@233
|
598 // m_plugin to 0 after deletion.
|
cannam@233
|
599 delete m_plugin;
|
cannam@233
|
600 m_plugin = 0;
|
cannam@233
|
601
|
cannam@233
|
602 if (m_loader) m_loader->pluginDeleted(this);
|
cannam@233
|
603 }
|
cannam@233
|
604
|
cannam@233
|
605 }
|
cannam@233
|
606
|
cannam@233
|
607 }
|
cannam@263
|
608
|
cannam@263
|
609 _VAMP_SDK_HOSTSPACE_END(PluginLoader.cpp)
|
cannam@263
|
610
|