Mercurial > hg > vamp-plugin-sdk
comparison host/vamp-simple-host.cpp @ 64:9d3272c7db60
* Merge from host-factory-stuff branch: this adds several helper classes in
the hostext directory that should make a host's life much easier. This
will become version 1.1 of the SDK, eventually.
author | cannam |
---|---|
date | Fri, 01 Jun 2007 15:10:17 +0000 |
parents | d3995d2b5e08 |
children | 6d16c376fd2f |
comparison
equal
deleted
inserted
replaced
54:933fee59d33a | 64:9d3272c7db60 |
---|---|
33 shall not be used in advertising or otherwise to promote the sale, | 33 shall not be used in advertising or otherwise to promote the sale, |
34 use or other dealings in this Software without prior written | 34 use or other dealings in this Software without prior written |
35 authorization. | 35 authorization. |
36 */ | 36 */ |
37 | 37 |
38 #include "PluginHostAdapter.h" | 38 #include "vamp-sdk/PluginHostAdapter.h" |
39 #include "vamp.h" | 39 #include "vamp-sdk/hostext/PluginChannelAdapter.h" |
40 #include "vamp-sdk/hostext/PluginInputDomainAdapter.h" | |
41 #include "vamp-sdk/hostext/PluginLoader.h" | |
42 #include "vamp/vamp.h" | |
40 | 43 |
41 #include <iostream> | 44 #include <iostream> |
42 #include <sndfile.h> | 45 #include <sndfile.h> |
43 #include <dirent.h> // POSIX directory open and read | |
44 | 46 |
45 #include "system.h" | 47 #include "system.h" |
46 | 48 |
47 #include <cmath> | 49 #include <cmath> |
48 | 50 |
50 using std::cerr; | 52 using std::cerr; |
51 using std::endl; | 53 using std::endl; |
52 using std::string; | 54 using std::string; |
53 using std::vector; | 55 using std::vector; |
54 | 56 |
55 #define HOST_VERSION "1.0" | 57 using Vamp::HostExt::PluginLoader; |
58 | |
59 #define HOST_VERSION "1.1" | |
56 | 60 |
57 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); | 61 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet); |
58 void transformInput(float *, size_t); | 62 void transformInput(float *, size_t); |
59 void fft(unsigned int, bool, double *, double *, double *, double *); | 63 void fft(unsigned int, bool, double *, double *, double *, double *); |
60 void printPluginPath(); | 64 void printPluginPath(bool verbose); |
61 | |
62 #ifdef HAVE_OPENDIR | |
63 void enumeratePlugins(); | 65 void enumeratePlugins(); |
64 #endif | 66 void listPluginsInLibrary(string soname); |
65 | 67 int runPlugin(string myname, string soname, string id, string output, |
66 /* | 68 int outputNo, string inputFile); |
67 A very simple Vamp plugin host. Given the name of a plugin | 69 |
68 library and the name of a sound file on the command line, it loads | 70 void usage(const char *name) |
69 the first plugin in the library and runs it on the sound file, | 71 { |
70 dumping the plugin's first output to stdout. | 72 cerr << "\n" |
71 */ | 73 << name << ": A simple Vamp plugin host.\n\n" |
74 "Centre for Digital Music, Queen Mary, University of London.\n" | |
75 "Copyright 2006-2007 Chris Cannam and QMUL.\n" | |
76 "Freely redistributable; published under a BSD-style license.\n\n" | |
77 "Usage:\n\n" | |
78 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav\n" | |
79 " " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno]\n\n" | |
80 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" | |
81 " audio data in \"file.wav\"; retrieve the named \"output\", or output\n" | |
82 " number \"outputno\" (the first output by default) and dump it to\n" | |
83 " standard output.\n\n" | |
84 " " << name << " -l\n\n" | |
85 " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n" | |
86 " " << name << " -p\n\n" | |
87 " -- Print out the Vamp plugin search path.\n\n" | |
88 " " << name << " -v\n\n" | |
89 " -- Display version information only.\n\n" | |
90 << endl; | |
91 exit(2); | |
92 } | |
72 | 93 |
73 int main(int argc, char **argv) | 94 int main(int argc, char **argv) |
74 { | 95 { |
75 if (argc < 2 || argc > 4) { | 96 char *scooter = argv[0]; |
76 char *scooter = argv[0]; | 97 char *name = 0; |
77 char *name = 0; | 98 while (scooter && *scooter) { |
78 while (scooter && *scooter) { | 99 if (*scooter == '/' || *scooter == '\\') name = ++scooter; |
79 if (*scooter == '/' || *scooter == '\\') name = ++scooter; | 100 else ++scooter; |
80 else ++scooter; | 101 } |
81 } | 102 if (!name || !*name) name = argv[0]; |
82 if (!name || !*name) name = argv[0]; | |
83 cerr << "\n" | |
84 << name << ": A simple Vamp plugin host.\n\n" | |
85 "Centre for Digital Music, Queen Mary, University of London.\n" | |
86 "Copyright 2006 Chris Cannam and QMUL.\n" | |
87 "Freely redistributable; published under a BSD-style license.\n\n" | |
88 "Usage:\n\n" | |
89 " " << name << " pluginlibrary." << PLUGIN_SUFFIX << "\n\n" | |
90 " -- Load \"pluginlibrary\" and list the Vamp plugins it contains.\n\n" | |
91 " " << name << " pluginlibrary." << PLUGIN_SUFFIX << ":plugin file.wav [outputno]\n\n" | |
92 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" | |
93 " audio data in \"file.wav\", dumping the output from \"outputno\"\n" | |
94 " (default 0) to standard output.\n\n" | |
95 #ifdef HAVE_OPENDIR | |
96 " " << name << " -l\n\n" | |
97 " -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n" | |
98 #endif | |
99 " " << name << " -p\n\n" | |
100 " -- Print out the Vamp plugin search path.\n\n" | |
101 " " << name << " -v\n\n" | |
102 " -- Display version information only.\n\n" | |
103 "Note that this host does not use the plugin search path when loadinga plugin.\nIf a plugin library is specified, it should be with a full file path.\n" | |
104 << endl; | |
105 return 2; | |
106 } | |
107 | 103 |
104 if (argc < 2 || argc > 4 || | |
105 (argc == 2 && | |
106 (!strcmp(argv[1], "-?") || | |
107 !strcmp(argv[1], "-h") || | |
108 !strcmp(argv[1], "--help")))) { | |
109 | |
110 usage(name); // does not return | |
111 } | |
112 | |
108 if (argc == 2 && !strcmp(argv[1], "-v")) { | 113 if (argc == 2 && !strcmp(argv[1], "-v")) { |
109 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl | 114 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl |
110 << "Vamp API version: " << VAMP_API_VERSION << endl | 115 << "Vamp API version: " << VAMP_API_VERSION << endl |
111 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; | 116 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; |
112 return 0; | 117 return 0; |
113 } | 118 } |
114 | 119 |
115 if (argc == 2 && !strcmp(argv[1], "-l")) { | 120 if (argc == 2 && !strcmp(argv[1], "-l")) { |
116 #ifdef HAVE_OPENDIR | 121 printPluginPath(true); |
117 enumeratePlugins(); | 122 enumeratePlugins(); |
118 #endif | |
119 return 0; | 123 return 0; |
120 } | 124 } |
121 if (argc == 2 && !strcmp(argv[1], "-p")) { | 125 if (argc == 2 && !strcmp(argv[1], "-p")) { |
122 printPluginPath(); | 126 printPluginPath(false); |
123 return 0; | 127 return 0; |
124 } | 128 } |
125 | 129 |
126 cerr << endl << argv[0] << ": Running..." << endl; | 130 cerr << endl << name << ": Running..." << endl; |
127 | 131 |
128 string soname = argv[1]; | 132 string soname = argv[1]; |
129 string plugid = ""; | 133 string plugid = ""; |
134 string output = ""; | |
135 int outputNo = -1; | |
130 string wavname; | 136 string wavname; |
131 if (argc >= 3) wavname = argv[2]; | 137 if (argc >= 3) wavname = argv[2]; |
132 | 138 |
133 int sep = soname.find(":"); | 139 string::size_type sep = soname.find(':'); |
134 if (sep >= 0 && sep < int(soname.length())) { | 140 |
141 if (sep != string::npos) { | |
135 plugid = soname.substr(sep + 1); | 142 plugid = soname.substr(sep + 1); |
136 soname = soname.substr(0, sep); | 143 soname = soname.substr(0, sep); |
137 } | 144 |
138 | 145 sep = plugid.find(':'); |
139 void *libraryHandle = DLOPEN(soname, RTLD_LAZY); | 146 if (sep != string::npos) { |
140 | 147 output = plugid.substr(sep + 1); |
141 if (!libraryHandle) { | 148 plugid = plugid.substr(0, sep); |
142 cerr << argv[0] << ": Failed to open plugin library " | 149 } |
143 << soname << ": " << DLERROR() << endl; | 150 } |
144 return 1; | 151 |
145 } | 152 if (plugid == "") { |
146 | 153 usage(name); |
147 cerr << argv[0] << ": Opened plugin library " << soname << endl; | 154 } |
148 | 155 |
149 VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction) | 156 if (argc == 4) outputNo = atoi(argv[3]); |
150 DLSYM(libraryHandle, "vampGetPluginDescriptor"); | 157 |
151 | 158 if (output != "" && outputNo != -1) { |
152 if (!fn) { | 159 usage(name); |
153 cerr << argv[0] << ": No Vamp descriptor function in library " | 160 } |
154 << soname << endl; | 161 |
155 DLCLOSE(libraryHandle); | 162 return runPlugin(name, soname, plugid, output, outputNo, wavname); |
156 return 1; | 163 } |
157 } | 164 |
158 | 165 |
159 cerr << argv[0] << ": Found plugin descriptor function" << endl; | 166 int runPlugin(string myname, string soname, string id, |
160 | 167 string output, int outputNo, string wavname) |
161 int index = 0; | 168 { |
162 int plugnumber = -1; | 169 PluginLoader *loader = PluginLoader::getInstance(); |
163 const VampPluginDescriptor *descriptor = 0; | 170 |
164 | 171 PluginLoader::PluginKey key = loader->composePluginKey(soname, id); |
165 while ((descriptor = fn(VAMP_API_VERSION, index))) { | |
166 | |
167 Vamp::PluginHostAdapter plugin(descriptor, 48000); | |
168 cerr << argv[0] << ": Plugin " << (index+1) | |
169 << " is \"" << plugin.getIdentifier() << "\"" << endl; | |
170 | |
171 if (plugin.getIdentifier() == plugid) plugnumber = index; | |
172 | |
173 ++index; | |
174 } | |
175 | |
176 cerr << argv[0] << ": Done\n" << endl; | |
177 | |
178 if (wavname == "") { | |
179 DLCLOSE(libraryHandle); | |
180 return 0; | |
181 } | |
182 | |
183 if (plugnumber < 0) { | |
184 if (plugid != "") { | |
185 cerr << "ERROR: No such plugin as " << plugid << " in library" | |
186 << endl; | |
187 DLCLOSE(libraryHandle); | |
188 return 0; | |
189 } else { | |
190 plugnumber = 0; | |
191 } | |
192 } | |
193 | |
194 descriptor = fn(VAMP_API_VERSION, plugnumber); | |
195 if (!descriptor) { | |
196 DLCLOSE(libraryHandle); | |
197 return 0; | |
198 } | |
199 | 172 |
200 SNDFILE *sndfile; | 173 SNDFILE *sndfile; |
201 SF_INFO sfinfo; | 174 SF_INFO sfinfo; |
202 memset(&sfinfo, 0, sizeof(SF_INFO)); | 175 memset(&sfinfo, 0, sizeof(SF_INFO)); |
203 | 176 |
204 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); | 177 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); |
205 if (!sndfile) { | 178 if (!sndfile) { |
206 cerr << "ERROR: Failed to open input file \"" << wavname << "\": " | 179 cerr << myname << ": ERROR: Failed to open input file \"" |
207 << sf_strerror(sndfile) << endl; | 180 << wavname << "\": " << sf_strerror(sndfile) << endl; |
208 DLCLOSE(libraryHandle); | |
209 return 1; | 181 return 1; |
210 } | 182 } |
211 | 183 |
212 Vamp::PluginHostAdapter *plugin = | 184 Vamp::Plugin *plugin = loader->loadPlugin |
213 new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate); | 185 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL); |
214 | 186 if (!plugin) { |
215 cerr << "Running " << plugin->getIdentifier() << "..." << endl; | 187 cerr << myname << ": ERROR: Failed to load plugin \"" << id |
188 << "\" from library \"" << soname << "\"" << endl; | |
189 sf_close(sndfile); | |
190 return 1; | |
191 } | |
192 | |
193 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; | |
216 | 194 |
217 int blockSize = plugin->getPreferredBlockSize(); | 195 int blockSize = plugin->getPreferredBlockSize(); |
218 int stepSize = plugin->getPreferredStepSize(); | 196 int stepSize = plugin->getPreferredStepSize(); |
219 | |
220 cerr << "Preferred block size = " << blockSize << ", step size = " | |
221 << stepSize << endl; | |
222 | |
223 if (blockSize == 0) blockSize = 1024; | |
224 | |
225 bool rightBlockSize = true; | |
226 | |
227 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { | |
228 | |
229 int p = 1, b = blockSize; | |
230 while (b) { | |
231 p <<= 1; | |
232 b >>= 1; | |
233 } | |
234 if (p != blockSize * 2) { | |
235 cerr << "WARNING: Plugin requested non-power-of-two block size of " | |
236 << blockSize << ",\nwhich is not supported by this host. "; | |
237 blockSize = p; | |
238 cerr << "Rounding up to " << blockSize << "." << endl; | |
239 rightBlockSize = false; | |
240 } | |
241 if (stepSize == 0) stepSize = blockSize / 2; | |
242 | |
243 } else { | |
244 | |
245 if (stepSize == 0) stepSize = blockSize; | |
246 } | |
247 | 197 |
248 int channels = sfinfo.channels; | 198 int channels = sfinfo.channels; |
249 | 199 |
250 float *filebuf = new float[blockSize * channels]; | 200 float *filebuf = new float[blockSize * channels]; |
251 float **plugbuf = new float*[channels]; | 201 float **plugbuf = new float*[channels]; |
255 << stepSize << endl; | 205 << stepSize << endl; |
256 | 206 |
257 int minch = plugin->getMinChannelCount(); | 207 int minch = plugin->getMinChannelCount(); |
258 int maxch = plugin->getMaxChannelCount(); | 208 int maxch = plugin->getMaxChannelCount(); |
259 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; | 209 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; |
210 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; | |
260 | 211 |
261 Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors(); | 212 Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors(); |
262 Vamp::Plugin::OutputDescriptor od; | 213 Vamp::Plugin::OutputDescriptor od; |
263 | 214 |
264 int returnValue = 1; | 215 int returnValue = 1; |
265 | 216 |
266 int output = 0; | 217 if (outputs.empty()) { |
267 if (argc == 4) output = atoi(argv[3]); | 218 cerr << "ERROR: Plugin has no outputs!" << endl; |
268 | 219 goto done; |
269 bool mix = false; | 220 } |
270 | 221 |
271 if (minch > channels || maxch < channels) { | 222 if (outputNo < 0) { |
272 if (minch == 1) { | 223 |
273 cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl; | 224 for (size_t oi = 0; oi < outputs.size(); ++oi) { |
274 mix = true; | 225 if (outputs[oi].identifier == output) { |
275 channels = 1; | 226 outputNo = oi; |
276 } else { | 227 break; |
277 cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl; | 228 } |
229 } | |
230 | |
231 if (outputNo < 0) { | |
232 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; | |
278 goto done; | 233 goto done; |
279 } | 234 } |
280 } | 235 |
281 | 236 } else { |
282 if (outputs.empty()) { | 237 |
283 cerr << "Plugin has no outputs!" << endl; | 238 if (int(outputs.size()) <= outputNo) { |
284 goto done; | 239 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; |
285 } | 240 goto done; |
286 | 241 } |
287 if (int(outputs.size()) <= output) { | 242 } |
288 cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; | 243 |
289 goto done; | 244 od = outputs[outputNo]; |
290 } | 245 cerr << "Output is: \"" << od.identifier << "\"" << endl; |
291 | |
292 od = outputs[output]; | |
293 cerr << "Output is " << od.identifier << endl; | |
294 | 246 |
295 if (!plugin->initialise(channels, stepSize, blockSize)) { | 247 if (!plugin->initialise(channels, stepSize, blockSize)) { |
296 cerr << "ERROR: Plugin initialise (channels = " << channels | 248 cerr << "ERROR: Plugin initialise (channels = " << channels |
297 << ", stepSize = " << stepSize << ", blockSize = " | 249 << ", stepSize = " << stepSize << ", blockSize = " |
298 << blockSize << ") failed." << endl; | 250 << blockSize << ") failed." << endl; |
299 if (!rightBlockSize) { | |
300 cerr << "(Probably because I couldn't provide the plugin's preferred block size.)" << endl; | |
301 } | |
302 goto done; | 251 goto done; |
303 } | 252 } |
304 | 253 |
305 for (size_t i = 0; i < sfinfo.frames; i += stepSize) { | 254 for (size_t i = 0; i < sfinfo.frames; i += stepSize) { |
306 | 255 |
315 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; | 264 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; |
316 break; | 265 break; |
317 } | 266 } |
318 | 267 |
319 for (int c = 0; c < channels; ++c) { | 268 for (int c = 0; c < channels; ++c) { |
320 for (int j = 0; j < blockSize; ++j) { | 269 int j = 0; |
270 while (j < count) { | |
271 plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; | |
272 ++j; | |
273 } | |
274 while (j < blockSize) { | |
321 plugbuf[c][j] = 0.0f; | 275 plugbuf[c][j] = 0.0f; |
322 } | 276 ++j; |
323 } | |
324 | |
325 for (int j = 0; j < blockSize && j < count; ++j) { | |
326 int tc = 0; | |
327 for (int c = 0; c < sfinfo.channels; ++c) { | |
328 tc = c; | |
329 if (mix) tc = 0; | |
330 plugbuf[tc][j] += filebuf[j * sfinfo.channels + c]; | |
331 } | |
332 if (mix) { | |
333 plugbuf[0][j] /= sfinfo.channels; | |
334 } | |
335 } | |
336 | |
337 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) { | |
338 for (int c = 0; c < sfinfo.channels; ++c) { | |
339 transformInput(plugbuf[c], blockSize); | |
340 if (mix) break; | |
341 } | 277 } |
342 } | 278 } |
343 | 279 |
344 printFeatures | 280 printFeatures |
345 (i, sfinfo.samplerate, output, plugin->process | 281 (i, sfinfo.samplerate, outputNo, plugin->process |
346 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); | 282 (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate))); |
347 } | 283 } |
348 | 284 |
349 printFeatures(sfinfo.frames, sfinfo.samplerate, output, | 285 printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo, |
350 plugin->getRemainingFeatures()); | 286 plugin->getRemainingFeatures()); |
351 | 287 |
352 returnValue = 0; | 288 returnValue = 0; |
353 | 289 |
354 done: | 290 done: |
355 delete plugin; | 291 delete plugin; |
356 | |
357 DLCLOSE(libraryHandle); | |
358 sf_close(sndfile); | 292 sf_close(sndfile); |
359 return returnValue; | 293 return returnValue; |
360 } | 294 } |
361 | 295 |
362 void | 296 void |
363 printPluginPath() | 297 printPluginPath(bool verbose) |
364 { | 298 { |
299 if (verbose) { | |
300 cout << "\nVamp plugin search path: "; | |
301 } | |
302 | |
365 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); | 303 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); |
366 for (size_t i = 0; i < path.size(); ++i) { | 304 for (size_t i = 0; i < path.size(); ++i) { |
367 cerr << path[i] << endl; | 305 if (verbose) { |
368 } | 306 cout << "[" << path[i] << "]"; |
369 } | 307 } else { |
370 | 308 cout << path[i] << endl; |
371 #ifdef HAVE_OPENDIR | 309 } |
310 } | |
311 | |
312 if (verbose) cout << endl; | |
313 } | |
372 | 314 |
373 void | 315 void |
374 enumeratePlugins() | 316 enumeratePlugins() |
375 { | 317 { |
376 cerr << endl << "Vamp plugin libraries found in search path:" << endl; | 318 PluginLoader *loader = PluginLoader::getInstance(); |
377 vector<string> path = Vamp::PluginHostAdapter::getPluginPath(); | 319 |
378 for (size_t i = 0; i < path.size(); ++i) { | 320 cout << "\nVamp plugin libraries found in search path:" << endl; |
379 cerr << "\n" << path[i] << ":" << endl; | 321 |
380 DIR *d = opendir(path[i].c_str()); | 322 std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); |
381 if (!d) { | 323 typedef std::multimap<std::string, PluginLoader::PluginKey> |
382 perror("Failed to open directory"); | 324 LibraryMap; |
383 continue; | 325 LibraryMap libraryMap; |
384 } | 326 |
385 struct dirent *e = 0; | 327 for (size_t i = 0; i < plugins.size(); ++i) { |
386 while ((e = readdir(d))) { | 328 std::string path = loader->getLibraryPathForPlugin(plugins[i]); |
387 // cerr << "reading: " << e->d_name << endl; | 329 libraryMap.insert(LibraryMap::value_type(path, plugins[i])); |
388 if (!(e->d_type & DT_REG)) { | 330 } |
389 // cerr << e->d_name << ": not a regular file" << endl; | 331 |
390 continue; | 332 std::string prevPath = ""; |
391 } | 333 int index = 0; |
392 int len = strlen(e->d_name); | 334 |
393 if (len < int(strlen(PLUGIN_SUFFIX) + 2) || | 335 for (LibraryMap::iterator i = libraryMap.begin(); |
394 e->d_name[len - strlen(PLUGIN_SUFFIX) - 1] != '.' || | 336 i != libraryMap.end(); ++i) { |
395 strcmp(e->d_name + len - strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX)) { | 337 |
396 // cerr << e->d_name << ": not a library file" << endl; | 338 std::string path = i->first; |
397 continue; | 339 PluginLoader::PluginKey key = i->second; |
398 } | 340 |
399 char *fp = new char[path[i].length() + len + 3]; | 341 if (path != prevPath) { |
400 sprintf(fp, "%s/%s", path[i].c_str(), e->d_name); | 342 prevPath = path; |
401 void *handle = DLOPEN(string(fp), RTLD_LAZY); | 343 index = 0; |
402 if (handle) { | 344 cout << "\n " << path << ":" << endl; |
403 VampGetPluginDescriptorFunction fn = | 345 } |
404 (VampGetPluginDescriptorFunction)DLSYM | 346 |
405 (handle, "vampGetPluginDescriptor"); | 347 Vamp::Plugin *plugin = loader->loadPlugin(key, 48000); |
406 if (fn) { | 348 if (plugin) { |
407 cerr << "\n " << e->d_name << ":" << endl; | 349 |
408 int index = 0; | 350 char c = char('A' + index); |
409 const VampPluginDescriptor *descriptor = 0; | 351 if (c > 'Z') c = char('a' + (index - 26)); |
410 while ((descriptor = fn(VAMP_API_VERSION, index))) { | 352 |
411 Vamp::PluginHostAdapter plugin(descriptor, 48000); | 353 cout << " [" << c << "] [v" |
412 char c = char('A' + index); | 354 << plugin->getVampApiVersion() << "] " |
413 if (c > 'Z') c = char('a' + (index - 26)); | 355 << plugin->getName() << ", \"" |
414 cerr << " [" << c << "] [v" | 356 << plugin->getIdentifier() << "\"" << " [" |
415 << plugin.getVampApiVersion() << "] " | 357 << plugin->getMaker() << "]" << endl; |
416 << plugin.getName() | 358 |
417 << ", \"" << plugin.getIdentifier() << "\"" | 359 PluginLoader::PluginCategoryHierarchy category = |
418 << " [" << plugin.getMaker() | 360 loader->getPluginCategory(key); |
419 << "]" << endl; | 361 if (!category.empty()) { |
420 if (plugin.getDescription() != "") { | 362 cout << " "; |
421 cerr << " - " << plugin.getDescription() << endl; | 363 for (size_t ci = 0; ci < category.size(); ++ci) { |
422 } | 364 cout << " > " << category[ci]; |
423 Vamp::Plugin::OutputList outputs = | 365 } |
424 plugin.getOutputDescriptors(); | 366 cout << endl; |
425 if (outputs.size() > 1) { | 367 } |
426 for (size_t j = 0; j < outputs.size(); ++j) { | 368 |
427 cerr << " (" << j << ") " | 369 if (plugin->getDescription() != "") { |
428 << outputs[j].name | 370 cout << " - " << plugin->getDescription() << endl; |
429 << ", \"" << outputs[j].identifier << "\"" | 371 } |
430 << endl; | 372 |
431 if (outputs[j].description != "") { | 373 Vamp::Plugin::OutputList outputs = |
432 cerr << " - " | 374 plugin->getOutputDescriptors(); |
433 << outputs[j].description << endl; | 375 |
434 } | 376 if (outputs.size() > 1) { |
435 } | 377 for (size_t j = 0; j < outputs.size(); ++j) { |
436 } | 378 cout << " (" << j << ") " |
437 ++index; | 379 << outputs[j].name << ", \"" |
380 << outputs[j].identifier << "\"" << endl; | |
381 if (outputs[j].description != "") { | |
382 cout << " - " | |
383 << outputs[j].description << endl; | |
438 } | 384 } |
439 } else { | |
440 // cerr << e->d_name << ": no Vamp descriptor function" << endl; | |
441 } | 385 } |
442 DLCLOSE(handle); | 386 } |
443 } else { | 387 |
444 cerr << "\n" << e->d_name << ": unable to load library (" << DLERROR() << ")" << endl; | 388 ++index; |
445 } | 389 |
446 } | 390 delete plugin; |
447 closedir(d); | 391 } |
448 } | 392 } |
449 cerr << endl; | 393 |
450 } | 394 cout << endl; |
451 | 395 } |
452 #endif | |
453 | |
454 | 396 |
455 void | 397 void |
456 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) | 398 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features) |
457 { | 399 { |
458 for (unsigned int i = 0; i < features[output].size(); ++i) { | 400 for (unsigned int i = 0; i < features[output].size(); ++i) { |
466 } | 408 } |
467 cout << endl; | 409 cout << endl; |
468 } | 410 } |
469 } | 411 } |
470 | 412 |
471 void | |
472 transformInput(float *buffer, size_t size) | |
473 { | |
474 double *inbuf = new double[size * 2]; | |
475 double *outbuf = new double[size * 2]; | |
476 | |
477 // Copy across with Hanning window | |
478 for (size_t i = 0; i < size; ++i) { | |
479 inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size)); | |
480 inbuf[i + size] = 0.0; | |
481 } | |
482 | |
483 for (size_t i = 0; i < size/2; ++i) { | |
484 double temp = inbuf[i]; | |
485 inbuf[i] = inbuf[i + size/2]; | |
486 inbuf[i + size/2] = temp; | |
487 } | |
488 | |
489 fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size); | |
490 | |
491 for (size_t i = 0; i <= size/2; ++i) { | |
492 buffer[i * 2] = outbuf[i]; | |
493 buffer[i * 2 + 1] = outbuf[i + size]; | |
494 } | |
495 | |
496 delete[] inbuf; | |
497 delete[] outbuf; | |
498 } | |
499 | |
500 void | |
501 fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io) | |
502 { | |
503 if (!ri || !ro || !io) return; | |
504 | |
505 unsigned int bits; | |
506 unsigned int i, j, k, m; | |
507 unsigned int blockSize, blockEnd; | |
508 | |
509 double tr, ti; | |
510 | |
511 if (n < 2) return; | |
512 if (n & (n-1)) return; | |
513 | |
514 double angle = 2.0 * M_PI; | |
515 if (inverse) angle = -angle; | |
516 | |
517 for (i = 0; ; ++i) { | |
518 if (n & (1 << i)) { | |
519 bits = i; | |
520 break; | |
521 } | |
522 } | |
523 | |
524 static unsigned int tableSize = 0; | |
525 static int *table = 0; | |
526 | |
527 if (tableSize != n) { | |
528 | |
529 delete[] table; | |
530 | |
531 table = new int[n]; | |
532 | |
533 for (i = 0; i < n; ++i) { | |
534 | |
535 m = i; | |
536 | |
537 for (j = k = 0; j < bits; ++j) { | |
538 k = (k << 1) | (m & 1); | |
539 m >>= 1; | |
540 } | |
541 | |
542 table[i] = k; | |
543 } | |
544 | |
545 tableSize = n; | |
546 } | |
547 | |
548 if (ii) { | |
549 for (i = 0; i < n; ++i) { | |
550 ro[table[i]] = ri[i]; | |
551 io[table[i]] = ii[i]; | |
552 } | |
553 } else { | |
554 for (i = 0; i < n; ++i) { | |
555 ro[table[i]] = ri[i]; | |
556 io[table[i]] = 0.0; | |
557 } | |
558 } | |
559 | |
560 blockEnd = 1; | |
561 | |
562 for (blockSize = 2; blockSize <= n; blockSize <<= 1) { | |
563 | |
564 double delta = angle / (double)blockSize; | |
565 double sm2 = -sin(-2 * delta); | |
566 double sm1 = -sin(-delta); | |
567 double cm2 = cos(-2 * delta); | |
568 double cm1 = cos(-delta); | |
569 double w = 2 * cm1; | |
570 double ar[3], ai[3]; | |
571 | |
572 for (i = 0; i < n; i += blockSize) { | |
573 | |
574 ar[2] = cm2; | |
575 ar[1] = cm1; | |
576 | |
577 ai[2] = sm2; | |
578 ai[1] = sm1; | |
579 | |
580 for (j = i, m = 0; m < blockEnd; j++, m++) { | |
581 | |
582 ar[0] = w * ar[1] - ar[2]; | |
583 ar[2] = ar[1]; | |
584 ar[1] = ar[0]; | |
585 | |
586 ai[0] = w * ai[1] - ai[2]; | |
587 ai[2] = ai[1]; | |
588 ai[1] = ai[0]; | |
589 | |
590 k = j + blockEnd; | |
591 tr = ar[0] * ro[k] - ai[0] * io[k]; | |
592 ti = ar[0] * io[k] + ai[0] * ro[k]; | |
593 | |
594 ro[k] = ro[j] - tr; | |
595 io[k] = io[j] - ti; | |
596 | |
597 ro[j] += tr; | |
598 io[j] += ti; | |
599 } | |
600 } | |
601 | |
602 blockEnd = blockSize; | |
603 } | |
604 | |
605 if (inverse) { | |
606 | |
607 double denom = (double)n; | |
608 | |
609 for (i = 0; i < n; i++) { | |
610 ro[i] /= denom; | |
611 io[i] /= denom; | |
612 } | |
613 } | |
614 } | |
615 | 413 |
616 | 414 |