Mercurial > hg > sv-dependency-builds
comparison src/vamp-plugin-sdk-2.5/host/vamp-simple-host.cpp @ 23:619f715526df sv_v2.1
Update Vamp plugin SDK to 2.5
author | Chris Cannam |
---|---|
date | Thu, 09 May 2013 10:52:46 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
22:b07fe9e906dc | 23:619f715526df |
---|---|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ | |
2 | |
3 /* | |
4 Vamp | |
5 | |
6 An API for audio analysis and feature extraction plugins. | |
7 | |
8 Centre for Digital Music, Queen Mary, University of London. | |
9 Copyright 2006 Chris Cannam, copyright 2007-2008 QMUL. | |
10 | |
11 Permission is hereby granted, free of charge, to any person | |
12 obtaining a copy of this software and associated documentation | |
13 files (the "Software"), to deal in the Software without | |
14 restriction, including without limitation the rights to use, copy, | |
15 modify, merge, publish, distribute, sublicense, and/or sell copies | |
16 of the Software, and to permit persons to whom the Software is | |
17 furnished to do so, subject to the following conditions: | |
18 | |
19 The above copyright notice and this permission notice shall be | |
20 included in all copies or substantial portions of the Software. | |
21 | |
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | |
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR | |
26 ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF | |
27 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
29 | |
30 Except as contained in this notice, the names of the Centre for | |
31 Digital Music; Queen Mary, University of London; and Chris Cannam | |
32 shall not be used in advertising or otherwise to promote the sale, | |
33 use or other dealings in this Software without prior written | |
34 authorization. | |
35 */ | |
36 | |
37 | |
38 /* | |
39 * This "simple" Vamp plugin host is no longer as simple as it was; it | |
40 * now has a lot of options and includes a lot of code to handle the | |
41 * various useful listing modes it supports. | |
42 * | |
43 * However, the runPlugin function still contains a reasonable | |
44 * implementation of a fairly generic Vamp plugin host capable of | |
45 * evaluating a given output on a given plugin for a sound file read | |
46 * via libsndfile. | |
47 */ | |
48 | |
49 #include <vamp-hostsdk/PluginHostAdapter.h> | |
50 #include <vamp-hostsdk/PluginInputDomainAdapter.h> | |
51 #include <vamp-hostsdk/PluginLoader.h> | |
52 | |
53 #include <iostream> | |
54 #include <fstream> | |
55 #include <set> | |
56 #include <sndfile.h> | |
57 | |
58 #include <cstring> | |
59 #include <cstdlib> | |
60 | |
61 #include "system.h" | |
62 | |
63 #include <cmath> | |
64 | |
65 using namespace std; | |
66 | |
67 using Vamp::Plugin; | |
68 using Vamp::PluginHostAdapter; | |
69 using Vamp::RealTime; | |
70 using Vamp::HostExt::PluginLoader; | |
71 using Vamp::HostExt::PluginWrapper; | |
72 using Vamp::HostExt::PluginInputDomainAdapter; | |
73 | |
74 #define HOST_VERSION "1.5" | |
75 | |
76 enum Verbosity { | |
77 PluginIds, | |
78 PluginOutputIds, | |
79 PluginInformation, | |
80 PluginInformationDetailed | |
81 }; | |
82 | |
83 void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); | |
84 void transformInput(float *, size_t); | |
85 void fft(unsigned int, bool, double *, double *, double *, double *); | |
86 void printPluginPath(bool verbose); | |
87 void printPluginCategoryList(); | |
88 void enumeratePlugins(Verbosity); | |
89 void listPluginsInLibrary(string soname); | |
90 int runPlugin(string myname, string soname, string id, string output, | |
91 int outputNo, string inputFile, string outfilename, bool frames); | |
92 | |
93 void usage(const char *name) | |
94 { | |
95 cerr << "\n" | |
96 << name << ": A command-line host for Vamp audio analysis plugins.\n\n" | |
97 "Centre for Digital Music, Queen Mary, University of London.\n" | |
98 "Copyright 2006-2009 Chris Cannam and QMUL.\n" | |
99 "Freely redistributable; published under a BSD-style license.\n\n" | |
100 "Usage:\n\n" | |
101 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" | |
102 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno] [-o out.txt]\n\n" | |
103 " -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n" | |
104 " audio data in \"file.wav\", retrieving the named \"output\", or output\n" | |
105 " number \"outputno\" (the first output by default) and dumping it to\n" | |
106 " standard output, or to \"out.txt\" if the -o option is given.\n\n" | |
107 " \"pluginlibrary\" should be a library name, not a file path; the\n" | |
108 " standard Vamp library search path will be used to locate it. If\n" | |
109 " a file path is supplied, the directory part(s) will be ignored.\n\n" | |
110 " If the -s option is given, results will be labelled with the audio\n" | |
111 " sample frame at which they occur. Otherwise, they will be labelled\n" | |
112 " with time in seconds.\n\n" | |
113 " " << name << " -l\n" | |
114 " " << name << " --list\n\n" | |
115 " -- List the plugin libraries and Vamp plugins in the library search path\n" | |
116 " in a verbose human-readable format.\n\n" | |
117 " " << name << " --list-full\n\n" | |
118 " -- List all data reported by all the Vamp plugins in the library search\n" | |
119 " path in a very verbose human-readable format.\n\n" | |
120 " " << name << " --list-ids\n\n" | |
121 " -- List the plugins in the search path in a terse machine-readable format,\n" | |
122 " in the form vamp:soname:identifier.\n\n" | |
123 " " << name << " --list-outputs\n\n" | |
124 " -- List the outputs for plugins in the search path in a machine-readable\n" | |
125 " format, in the form vamp:soname:identifier:output.\n\n" | |
126 " " << name << " --list-by-category\n\n" | |
127 " -- List the plugins as a plugin index by category, in a machine-readable\n" | |
128 " format. The format may change in future releases.\n\n" | |
129 " " << name << " -p\n\n" | |
130 " -- Print out the Vamp library search path.\n\n" | |
131 " " << name << " -v\n\n" | |
132 " -- Display version information only.\n" | |
133 << endl; | |
134 exit(2); | |
135 } | |
136 | |
137 int main(int argc, char **argv) | |
138 { | |
139 char *scooter = argv[0]; | |
140 char *name = 0; | |
141 while (scooter && *scooter) { | |
142 if (*scooter == '/' || *scooter == '\\') name = ++scooter; | |
143 else ++scooter; | |
144 } | |
145 if (!name || !*name) name = argv[0]; | |
146 | |
147 if (argc < 2) usage(name); | |
148 | |
149 if (argc == 2) { | |
150 | |
151 if (!strcmp(argv[1], "-v")) { | |
152 | |
153 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl | |
154 << "Vamp API version: " << VAMP_API_VERSION << endl | |
155 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; | |
156 return 0; | |
157 | |
158 } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) { | |
159 | |
160 printPluginPath(true); | |
161 enumeratePlugins(PluginInformation); | |
162 return 0; | |
163 | |
164 } else if (!strcmp(argv[1], "--list-full")) { | |
165 | |
166 enumeratePlugins(PluginInformationDetailed); | |
167 return 0; | |
168 | |
169 } else if (!strcmp(argv[1], "-p")) { | |
170 | |
171 printPluginPath(false); | |
172 return 0; | |
173 | |
174 } else if (!strcmp(argv[1], "--list-ids")) { | |
175 | |
176 enumeratePlugins(PluginIds); | |
177 return 0; | |
178 | |
179 } else if (!strcmp(argv[1], "--list-outputs")) { | |
180 | |
181 enumeratePlugins(PluginOutputIds); | |
182 return 0; | |
183 | |
184 } else if (!strcmp(argv[1], "--list-by-category")) { | |
185 | |
186 printPluginCategoryList(); | |
187 return 0; | |
188 | |
189 } else usage(name); | |
190 } | |
191 | |
192 if (argc < 3) usage(name); | |
193 | |
194 bool useFrames = false; | |
195 | |
196 int base = 1; | |
197 if (!strcmp(argv[1], "-s")) { | |
198 useFrames = true; | |
199 base = 2; | |
200 } | |
201 | |
202 string soname = argv[base]; | |
203 string wavname = argv[base+1]; | |
204 string plugid = ""; | |
205 string output = ""; | |
206 int outputNo = -1; | |
207 string outfilename; | |
208 | |
209 if (argc >= base+3) { | |
210 | |
211 int idx = base+2; | |
212 | |
213 if (isdigit(*argv[idx])) { | |
214 outputNo = atoi(argv[idx++]); | |
215 } | |
216 | |
217 if (argc == idx + 2) { | |
218 if (!strcmp(argv[idx], "-o")) { | |
219 outfilename = argv[idx+1]; | |
220 } else usage(name); | |
221 } else if (argc != idx) { | |
222 (usage(name)); | |
223 } | |
224 } | |
225 | |
226 cerr << endl << name << ": Running..." << endl; | |
227 | |
228 cerr << "Reading file: \"" << wavname << "\", writing to "; | |
229 if (outfilename == "") { | |
230 cerr << "standard output" << endl; | |
231 } else { | |
232 cerr << "\"" << outfilename << "\"" << endl; | |
233 } | |
234 | |
235 string::size_type sep = soname.find(':'); | |
236 | |
237 if (sep != string::npos) { | |
238 plugid = soname.substr(sep + 1); | |
239 soname = soname.substr(0, sep); | |
240 | |
241 sep = plugid.find(':'); | |
242 if (sep != string::npos) { | |
243 output = plugid.substr(sep + 1); | |
244 plugid = plugid.substr(0, sep); | |
245 } | |
246 } | |
247 | |
248 if (plugid == "") { | |
249 usage(name); | |
250 } | |
251 | |
252 if (output != "" && outputNo != -1) { | |
253 usage(name); | |
254 } | |
255 | |
256 if (output == "" && outputNo == -1) { | |
257 outputNo = 0; | |
258 } | |
259 | |
260 return runPlugin(name, soname, plugid, output, outputNo, | |
261 wavname, outfilename, useFrames); | |
262 } | |
263 | |
264 | |
265 int runPlugin(string myname, string soname, string id, | |
266 string output, int outputNo, string wavname, | |
267 string outfilename, bool useFrames) | |
268 { | |
269 PluginLoader *loader = PluginLoader::getInstance(); | |
270 | |
271 PluginLoader::PluginKey key = loader->composePluginKey(soname, id); | |
272 | |
273 SNDFILE *sndfile; | |
274 SF_INFO sfinfo; | |
275 memset(&sfinfo, 0, sizeof(SF_INFO)); | |
276 | |
277 sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo); | |
278 if (!sndfile) { | |
279 cerr << myname << ": ERROR: Failed to open input file \"" | |
280 << wavname << "\": " << sf_strerror(sndfile) << endl; | |
281 return 1; | |
282 } | |
283 | |
284 ofstream *out = 0; | |
285 if (outfilename != "") { | |
286 out = new ofstream(outfilename.c_str(), ios::out); | |
287 if (!*out) { | |
288 cerr << myname << ": ERROR: Failed to open output file \"" | |
289 << outfilename << "\" for writing" << endl; | |
290 delete out; | |
291 return 1; | |
292 } | |
293 } | |
294 | |
295 Plugin *plugin = loader->loadPlugin | |
296 (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL_SAFE); | |
297 if (!plugin) { | |
298 cerr << myname << ": ERROR: Failed to load plugin \"" << id | |
299 << "\" from library \"" << soname << "\"" << endl; | |
300 sf_close(sndfile); | |
301 if (out) { | |
302 out->close(); | |
303 delete out; | |
304 } | |
305 return 1; | |
306 } | |
307 | |
308 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; | |
309 | |
310 // Note that the following would be much simpler if we used a | |
311 // PluginBufferingAdapter as well -- i.e. if we had passed | |
312 // PluginLoader::ADAPT_ALL to loader->loadPlugin() above, instead | |
313 // of ADAPT_ALL_SAFE. Then we could simply specify our own block | |
314 // size, keep the step size equal to the block size, and ignore | |
315 // the plugin's bleatings. However, there are some issues with | |
316 // using a PluginBufferingAdapter that make the results sometimes | |
317 // technically different from (if effectively the same as) the | |
318 // un-adapted plugin, so we aren't doing that here. See the | |
319 // PluginBufferingAdapter documentation for details. | |
320 | |
321 int blockSize = plugin->getPreferredBlockSize(); | |
322 int stepSize = plugin->getPreferredStepSize(); | |
323 | |
324 if (blockSize == 0) { | |
325 blockSize = 1024; | |
326 } | |
327 if (stepSize == 0) { | |
328 if (plugin->getInputDomain() == Plugin::FrequencyDomain) { | |
329 stepSize = blockSize/2; | |
330 } else { | |
331 stepSize = blockSize; | |
332 } | |
333 } else if (stepSize > blockSize) { | |
334 cerr << "WARNING: stepSize " << stepSize << " > blockSize " << blockSize << ", resetting blockSize to "; | |
335 if (plugin->getInputDomain() == Plugin::FrequencyDomain) { | |
336 blockSize = stepSize * 2; | |
337 } else { | |
338 blockSize = stepSize; | |
339 } | |
340 cerr << blockSize << endl; | |
341 } | |
342 int overlapSize = blockSize - stepSize; | |
343 sf_count_t currentStep = 0; | |
344 int finalStepsRemaining = max(1, (blockSize / stepSize) - 1); // at end of file, this many part-silent frames needed after we hit EOF | |
345 | |
346 int channels = sfinfo.channels; | |
347 | |
348 float *filebuf = new float[blockSize * channels]; | |
349 float **plugbuf = new float*[channels]; | |
350 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; | |
351 | |
352 cerr << "Using block size = " << blockSize << ", step size = " | |
353 << stepSize << endl; | |
354 | |
355 // The channel queries here are for informational purposes only -- | |
356 // a PluginChannelAdapter is being used automatically behind the | |
357 // scenes, and it will take case of any channel mismatch | |
358 | |
359 int minch = plugin->getMinChannelCount(); | |
360 int maxch = plugin->getMaxChannelCount(); | |
361 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; | |
362 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; | |
363 | |
364 Plugin::OutputList outputs = plugin->getOutputDescriptors(); | |
365 Plugin::OutputDescriptor od; | |
366 | |
367 int returnValue = 1; | |
368 int progress = 0; | |
369 | |
370 RealTime rt; | |
371 PluginWrapper *wrapper = 0; | |
372 RealTime adjustment = RealTime::zeroTime; | |
373 | |
374 if (outputs.empty()) { | |
375 cerr << "ERROR: Plugin has no outputs!" << endl; | |
376 goto done; | |
377 } | |
378 | |
379 if (outputNo < 0) { | |
380 | |
381 for (size_t oi = 0; oi < outputs.size(); ++oi) { | |
382 if (outputs[oi].identifier == output) { | |
383 outputNo = oi; | |
384 break; | |
385 } | |
386 } | |
387 | |
388 if (outputNo < 0) { | |
389 cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl; | |
390 goto done; | |
391 } | |
392 | |
393 } else { | |
394 | |
395 if (int(outputs.size()) <= outputNo) { | |
396 cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl; | |
397 goto done; | |
398 } | |
399 } | |
400 | |
401 od = outputs[outputNo]; | |
402 cerr << "Output is: \"" << od.identifier << "\"" << endl; | |
403 | |
404 if (!plugin->initialise(channels, stepSize, blockSize)) { | |
405 cerr << "ERROR: Plugin initialise (channels = " << channels | |
406 << ", stepSize = " << stepSize << ", blockSize = " | |
407 << blockSize << ") failed." << endl; | |
408 goto done; | |
409 } | |
410 | |
411 wrapper = dynamic_cast<PluginWrapper *>(plugin); | |
412 if (wrapper) { | |
413 // See documentation for | |
414 // PluginInputDomainAdapter::getTimestampAdjustment | |
415 PluginInputDomainAdapter *ida = | |
416 wrapper->getWrapper<PluginInputDomainAdapter>(); | |
417 if (ida) adjustment = ida->getTimestampAdjustment(); | |
418 } | |
419 | |
420 // Here we iterate over the frames, avoiding asking the numframes in case it's streaming input. | |
421 do { | |
422 | |
423 int count; | |
424 | |
425 if ((blockSize==stepSize) || (currentStep==0)) { | |
426 // read a full fresh block | |
427 if ((count = sf_readf_float(sndfile, filebuf, blockSize)) < 0) { | |
428 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; | |
429 break; | |
430 } | |
431 if (count != blockSize) --finalStepsRemaining; | |
432 } else { | |
433 // otherwise shunt the existing data down and read the remainder. | |
434 memmove(filebuf, filebuf + (stepSize * channels), overlapSize * channels * sizeof(float)); | |
435 if ((count = sf_readf_float(sndfile, filebuf + (overlapSize * channels), stepSize)) < 0) { | |
436 cerr << "ERROR: sf_readf_float failed: " << sf_strerror(sndfile) << endl; | |
437 break; | |
438 } | |
439 if (count != stepSize) --finalStepsRemaining; | |
440 count += overlapSize; | |
441 } | |
442 | |
443 for (int c = 0; c < channels; ++c) { | |
444 int j = 0; | |
445 while (j < count) { | |
446 plugbuf[c][j] = filebuf[j * sfinfo.channels + c]; | |
447 ++j; | |
448 } | |
449 while (j < blockSize) { | |
450 plugbuf[c][j] = 0.0f; | |
451 ++j; | |
452 } | |
453 } | |
454 | |
455 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); | |
456 | |
457 printFeatures | |
458 (RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), | |
459 sfinfo.samplerate, outputNo, plugin->process(plugbuf, rt), | |
460 out, useFrames); | |
461 | |
462 if (sfinfo.frames > 0){ | |
463 int pp = progress; | |
464 progress = lrintf((float(currentStep * stepSize) / sfinfo.frames) * 100.f); | |
465 if (progress != pp && out) { | |
466 cerr << "\r" << progress << "%"; | |
467 } | |
468 } | |
469 | |
470 ++currentStep; | |
471 | |
472 } while (finalStepsRemaining > 0); | |
473 | |
474 if (out) cerr << "\rDone" << endl; | |
475 | |
476 rt = RealTime::frame2RealTime(currentStep * stepSize, sfinfo.samplerate); | |
477 | |
478 printFeatures(RealTime::realTime2Frame(rt + adjustment, sfinfo.samplerate), | |
479 sfinfo.samplerate, outputNo, | |
480 plugin->getRemainingFeatures(), out, useFrames); | |
481 | |
482 returnValue = 0; | |
483 | |
484 done: | |
485 delete plugin; | |
486 if (out) { | |
487 out->close(); | |
488 delete out; | |
489 } | |
490 sf_close(sndfile); | |
491 return returnValue; | |
492 } | |
493 | |
494 void | |
495 printFeatures(int frame, int sr, int output, | |
496 Plugin::FeatureSet features, ofstream *out, bool useFrames) | |
497 { | |
498 for (unsigned int i = 0; i < features[output].size(); ++i) { | |
499 | |
500 if (useFrames) { | |
501 | |
502 int displayFrame = frame; | |
503 | |
504 if (features[output][i].hasTimestamp) { | |
505 displayFrame = RealTime::realTime2Frame | |
506 (features[output][i].timestamp, sr); | |
507 } | |
508 | |
509 (out ? *out : cout) << displayFrame; | |
510 | |
511 if (features[output][i].hasDuration) { | |
512 displayFrame = RealTime::realTime2Frame | |
513 (features[output][i].duration, sr); | |
514 (out ? *out : cout) << "," << displayFrame; | |
515 } | |
516 | |
517 (out ? *out : cout) << ":"; | |
518 | |
519 } else { | |
520 | |
521 RealTime rt = RealTime::frame2RealTime(frame, sr); | |
522 | |
523 if (features[output][i].hasTimestamp) { | |
524 rt = features[output][i].timestamp; | |
525 } | |
526 | |
527 (out ? *out : cout) << rt.toString(); | |
528 | |
529 if (features[output][i].hasDuration) { | |
530 rt = features[output][i].duration; | |
531 (out ? *out : cout) << "," << rt.toString(); | |
532 } | |
533 | |
534 (out ? *out : cout) << ":"; | |
535 } | |
536 | |
537 for (unsigned int j = 0; j < features[output][i].values.size(); ++j) { | |
538 (out ? *out : cout) << " " << features[output][i].values[j]; | |
539 } | |
540 (out ? *out : cout) << " " << features[output][i].label; | |
541 | |
542 (out ? *out : cout) << endl; | |
543 } | |
544 } | |
545 | |
546 void | |
547 printPluginPath(bool verbose) | |
548 { | |
549 if (verbose) { | |
550 cout << "\nVamp plugin search path: "; | |
551 } | |
552 | |
553 vector<string> path = PluginHostAdapter::getPluginPath(); | |
554 for (size_t i = 0; i < path.size(); ++i) { | |
555 if (verbose) { | |
556 cout << "[" << path[i] << "]"; | |
557 } else { | |
558 cout << path[i] << endl; | |
559 } | |
560 } | |
561 | |
562 if (verbose) cout << endl; | |
563 } | |
564 | |
565 static | |
566 string | |
567 header(string text, int level) | |
568 { | |
569 string out = '\n' + text + '\n'; | |
570 for (size_t i = 0; i < text.length(); ++i) { | |
571 out += (level == 1 ? '=' : level == 2 ? '-' : '~'); | |
572 } | |
573 out += '\n'; | |
574 return out; | |
575 } | |
576 | |
577 void | |
578 enumeratePlugins(Verbosity verbosity) | |
579 { | |
580 PluginLoader *loader = PluginLoader::getInstance(); | |
581 | |
582 if (verbosity == PluginInformation) { | |
583 cout << "\nVamp plugin libraries found in search path:" << endl; | |
584 } | |
585 | |
586 vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); | |
587 typedef multimap<string, PluginLoader::PluginKey> | |
588 LibraryMap; | |
589 LibraryMap libraryMap; | |
590 | |
591 for (size_t i = 0; i < plugins.size(); ++i) { | |
592 string path = loader->getLibraryPathForPlugin(plugins[i]); | |
593 libraryMap.insert(LibraryMap::value_type(path, plugins[i])); | |
594 } | |
595 | |
596 string prevPath = ""; | |
597 int index = 0; | |
598 | |
599 for (LibraryMap::iterator i = libraryMap.begin(); | |
600 i != libraryMap.end(); ++i) { | |
601 | |
602 string path = i->first; | |
603 PluginLoader::PluginKey key = i->second; | |
604 | |
605 if (path != prevPath) { | |
606 prevPath = path; | |
607 index = 0; | |
608 if (verbosity == PluginInformation) { | |
609 cout << "\n " << path << ":" << endl; | |
610 } else if (verbosity == PluginInformationDetailed) { | |
611 string::size_type ki = i->second.find(':'); | |
612 string text = "Library \"" + i->second.substr(0, ki) + "\""; | |
613 cout << "\n" << header(text, 1); | |
614 } | |
615 } | |
616 | |
617 Plugin *plugin = loader->loadPlugin(key, 48000); | |
618 if (plugin) { | |
619 | |
620 char c = char('A' + index); | |
621 if (c > 'Z') c = char('a' + (index - 26)); | |
622 | |
623 PluginLoader::PluginCategoryHierarchy category = | |
624 loader->getPluginCategory(key); | |
625 string catstr; | |
626 if (!category.empty()) { | |
627 for (size_t ci = 0; ci < category.size(); ++ci) { | |
628 if (ci > 0) catstr += " > "; | |
629 catstr += category[ci]; | |
630 } | |
631 } | |
632 | |
633 if (verbosity == PluginInformation) { | |
634 | |
635 cout << " [" << c << "] [v" | |
636 << plugin->getVampApiVersion() << "] " | |
637 << plugin->getName() << ", \"" | |
638 << plugin->getIdentifier() << "\"" << " [" | |
639 << plugin->getMaker() << "]" << endl; | |
640 | |
641 if (catstr != "") { | |
642 cout << " > " << catstr << endl; | |
643 } | |
644 | |
645 if (plugin->getDescription() != "") { | |
646 cout << " - " << plugin->getDescription() << endl; | |
647 } | |
648 | |
649 } else if (verbosity == PluginInformationDetailed) { | |
650 | |
651 cout << header(plugin->getName(), 2); | |
652 cout << " - Identifier: " | |
653 << key << endl; | |
654 cout << " - Plugin Version: " | |
655 << plugin->getPluginVersion() << endl; | |
656 cout << " - Vamp API Version: " | |
657 << plugin->getVampApiVersion() << endl; | |
658 cout << " - Maker: \"" | |
659 << plugin->getMaker() << "\"" << endl; | |
660 cout << " - Copyright: \"" | |
661 << plugin->getCopyright() << "\"" << endl; | |
662 cout << " - Description: \"" | |
663 << plugin->getDescription() << "\"" << endl; | |
664 cout << " - Input Domain: " | |
665 << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? | |
666 "Time Domain" : "Frequency Domain") << endl; | |
667 cout << " - Default Step Size: " | |
668 << plugin->getPreferredStepSize() << endl; | |
669 cout << " - Default Block Size: " | |
670 << plugin->getPreferredBlockSize() << endl; | |
671 cout << " - Minimum Channels: " | |
672 << plugin->getMinChannelCount() << endl; | |
673 cout << " - Maximum Channels: " | |
674 << plugin->getMaxChannelCount() << endl; | |
675 | |
676 } else if (verbosity == PluginIds) { | |
677 cout << "vamp:" << key << endl; | |
678 } | |
679 | |
680 Plugin::OutputList outputs = | |
681 plugin->getOutputDescriptors(); | |
682 | |
683 if (verbosity == PluginInformationDetailed) { | |
684 | |
685 Plugin::ParameterList params = plugin->getParameterDescriptors(); | |
686 for (size_t j = 0; j < params.size(); ++j) { | |
687 Plugin::ParameterDescriptor &pd(params[j]); | |
688 cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; | |
689 cout << " - Identifier: " << pd.identifier << endl; | |
690 cout << " - Description: \"" << pd.description << "\"" << endl; | |
691 if (pd.unit != "") { | |
692 cout << " - Unit: " << pd.unit << endl; | |
693 } | |
694 cout << " - Range: "; | |
695 cout << pd.minValue << " -> " << pd.maxValue << endl; | |
696 cout << " - Default: "; | |
697 cout << pd.defaultValue << endl; | |
698 if (pd.isQuantized) { | |
699 cout << " - Quantize Step: " | |
700 << pd.quantizeStep << endl; | |
701 } | |
702 if (!pd.valueNames.empty()) { | |
703 cout << " - Value Names: "; | |
704 for (size_t k = 0; k < pd.valueNames.size(); ++k) { | |
705 if (k > 0) cout << ", "; | |
706 cout << "\"" << pd.valueNames[k] << "\""; | |
707 } | |
708 cout << endl; | |
709 } | |
710 } | |
711 | |
712 if (outputs.empty()) { | |
713 cout << "\n** Note: This plugin reports no outputs!" << endl; | |
714 } | |
715 for (size_t j = 0; j < outputs.size(); ++j) { | |
716 Plugin::OutputDescriptor &od(outputs[j]); | |
717 cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; | |
718 cout << " - Identifier: " << od.identifier << endl; | |
719 cout << " - Description: \"" << od.description << "\"" << endl; | |
720 if (od.unit != "") { | |
721 cout << " - Unit: " << od.unit << endl; | |
722 } | |
723 if (od.hasFixedBinCount) { | |
724 cout << " - Default Bin Count: " << od.binCount << endl; | |
725 } | |
726 if (!od.binNames.empty()) { | |
727 bool have = false; | |
728 for (size_t k = 0; k < od.binNames.size(); ++k) { | |
729 if (od.binNames[k] != "") { | |
730 have = true; break; | |
731 } | |
732 } | |
733 if (have) { | |
734 cout << " - Bin Names: "; | |
735 for (size_t k = 0; k < od.binNames.size(); ++k) { | |
736 if (k > 0) cout << ", "; | |
737 cout << "\"" << od.binNames[k] << "\""; | |
738 } | |
739 cout << endl; | |
740 } | |
741 } | |
742 if (od.hasKnownExtents) { | |
743 cout << " - Default Extents: "; | |
744 cout << od.minValue << " -> " << od.maxValue << endl; | |
745 } | |
746 if (od.isQuantized) { | |
747 cout << " - Quantize Step: " | |
748 << od.quantizeStep << endl; | |
749 } | |
750 cout << " - Sample Type: " | |
751 << (od.sampleType == | |
752 Plugin::OutputDescriptor::OneSamplePerStep ? | |
753 "One Sample Per Step" : | |
754 od.sampleType == | |
755 Plugin::OutputDescriptor::FixedSampleRate ? | |
756 "Fixed Sample Rate" : | |
757 "Variable Sample Rate") << endl; | |
758 if (od.sampleType != | |
759 Plugin::OutputDescriptor::OneSamplePerStep) { | |
760 cout << " - Default Rate: " | |
761 << od.sampleRate << endl; | |
762 } | |
763 cout << " - Has Duration: " | |
764 << (od.hasDuration ? "Yes" : "No") << endl; | |
765 } | |
766 } | |
767 | |
768 if (outputs.size() > 1 || verbosity == PluginOutputIds) { | |
769 for (size_t j = 0; j < outputs.size(); ++j) { | |
770 if (verbosity == PluginInformation) { | |
771 cout << " (" << j << ") " | |
772 << outputs[j].name << ", \"" | |
773 << outputs[j].identifier << "\"" << endl; | |
774 if (outputs[j].description != "") { | |
775 cout << " - " | |
776 << outputs[j].description << endl; | |
777 } | |
778 } else if (verbosity == PluginOutputIds) { | |
779 cout << "vamp:" << key << ":" << outputs[j].identifier << endl; | |
780 } | |
781 } | |
782 } | |
783 | |
784 ++index; | |
785 | |
786 delete plugin; | |
787 } | |
788 } | |
789 | |
790 if (verbosity == PluginInformation || | |
791 verbosity == PluginInformationDetailed) { | |
792 cout << endl; | |
793 } | |
794 } | |
795 | |
796 void | |
797 printPluginCategoryList() | |
798 { | |
799 PluginLoader *loader = PluginLoader::getInstance(); | |
800 | |
801 vector<PluginLoader::PluginKey> plugins = loader->listPlugins(); | |
802 | |
803 set<string> printedcats; | |
804 | |
805 for (size_t i = 0; i < plugins.size(); ++i) { | |
806 | |
807 PluginLoader::PluginKey key = plugins[i]; | |
808 | |
809 PluginLoader::PluginCategoryHierarchy category = | |
810 loader->getPluginCategory(key); | |
811 | |
812 Plugin *plugin = loader->loadPlugin(key, 48000); | |
813 if (!plugin) continue; | |
814 | |
815 string catstr = ""; | |
816 | |
817 if (category.empty()) catstr = '|'; | |
818 else { | |
819 for (size_t j = 0; j < category.size(); ++j) { | |
820 catstr += category[j]; | |
821 catstr += '|'; | |
822 if (printedcats.find(catstr) == printedcats.end()) { | |
823 std::cout << catstr << std::endl; | |
824 printedcats.insert(catstr); | |
825 } | |
826 } | |
827 } | |
828 | |
829 std::cout << catstr << key << ":::" << plugin->getName() << ":::" << plugin->getMaker() << ":::" << plugin->getDescription() << std::endl; | |
830 } | |
831 } | |
832 |