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