Mercurial > hg > vamp-plugin-sdk
comparison host/vamp-simple-host.cpp @ 240:7b90fe049d04
* Add --list-full to "simple" Vamp host
author | cannam |
---|---|
date | Mon, 10 Nov 2008 16:47:41 +0000 |
parents | 521734d2b498 |
children | 70e6826adc64 |
comparison
equal
deleted
inserted
replaced
239:cc467e52da4c | 240:7b90fe049d04 |
---|---|
5 | 5 |
6 An API for audio analysis and feature extraction plugins. | 6 An API for audio analysis and feature extraction plugins. |
7 | 7 |
8 Centre for Digital Music, Queen Mary, University of London. | 8 Centre for Digital Music, Queen Mary, University of London. |
9 Copyright 2006 Chris Cannam. | 9 Copyright 2006 Chris Cannam. |
10 FFT code from Don Cross's public domain FFT implementation. | |
11 | 10 |
12 Permission is hereby granted, free of charge, to any person | 11 Permission is hereby granted, free of charge, to any person |
13 obtaining a copy of this software and associated documentation | 12 obtaining a copy of this software and associated documentation |
14 files (the "Software"), to deal in the Software without | 13 files (the "Software"), to deal in the Software without |
15 restriction, including without limitation the rights to use, copy, | 14 restriction, including without limitation the rights to use, copy, |
33 shall not be used in advertising or otherwise to promote the sale, | 32 shall not be used in advertising or otherwise to promote the sale, |
34 use or other dealings in this Software without prior written | 33 use or other dealings in this Software without prior written |
35 authorization. | 34 authorization. |
36 */ | 35 */ |
37 | 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 list options 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 | |
38 #include <vamp-hostsdk/PluginHostAdapter.h> | 49 #include <vamp-hostsdk/PluginHostAdapter.h> |
39 #include <vamp-hostsdk/PluginInputDomainAdapter.h> | 50 #include <vamp-hostsdk/PluginInputDomainAdapter.h> |
40 #include <vamp-hostsdk/PluginLoader.h> | 51 #include <vamp-hostsdk/PluginLoader.h> |
41 | 52 |
42 #include <iostream> | 53 #include <iostream> |
58 using Vamp::RealTime; | 69 using Vamp::RealTime; |
59 using Vamp::HostExt::PluginLoader; | 70 using Vamp::HostExt::PluginLoader; |
60 using Vamp::HostExt::PluginWrapper; | 71 using Vamp::HostExt::PluginWrapper; |
61 using Vamp::HostExt::PluginInputDomainAdapter; | 72 using Vamp::HostExt::PluginInputDomainAdapter; |
62 | 73 |
63 #define HOST_VERSION "1.3" | 74 #define HOST_VERSION "1.4" |
64 | 75 |
65 enum Verbosity { | 76 enum Verbosity { |
66 PluginIds, | 77 PluginIds, |
67 PluginOutputIds, | 78 PluginOutputIds, |
68 PluginInformation | 79 PluginInformation, |
80 PluginInformationDetailed | |
69 }; | 81 }; |
70 | 82 |
71 void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); | 83 void printFeatures(int, int, int, Plugin::FeatureSet, ofstream *, bool frames); |
72 void transformInput(float *, size_t); | 84 void transformInput(float *, size_t); |
73 void fft(unsigned int, bool, double *, double *, double *, double *); | 85 void fft(unsigned int, bool, double *, double *, double *, double *); |
79 int outputNo, string inputFile, string outfilename, bool frames); | 91 int outputNo, string inputFile, string outfilename, bool frames); |
80 | 92 |
81 void usage(const char *name) | 93 void usage(const char *name) |
82 { | 94 { |
83 cerr << "\n" | 95 cerr << "\n" |
84 << name << ": A simple Vamp plugin host.\n\n" | 96 << name << ": A command-line host for Vamp audio analysis plugins.\n\n" |
85 "Centre for Digital Music, Queen Mary, University of London.\n" | 97 "Centre for Digital Music, Queen Mary, University of London.\n" |
86 "Copyright 2006-2007 Chris Cannam and QMUL.\n" | 98 "Copyright 2006-2007 Chris Cannam and QMUL.\n" |
87 "Freely redistributable; published under a BSD-style license.\n\n" | 99 "Freely redistributable; published under a BSD-style license.\n\n" |
88 "Usage:\n\n" | 100 "Usage:\n\n" |
89 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" | 101 " " << name << " [-s] pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav [-o out.txt]\n" |
96 " standard Vamp library search path will be used to locate it. If\n" | 108 " standard Vamp library search path will be used to locate it. If\n" |
97 " a file path is supplied, the directory part(s) will be ignored.\n\n" | 109 " a file path is supplied, the directory part(s) will be ignored.\n\n" |
98 " If the -s option is given, results will be labelled with the audio\n" | 110 " If the -s option is given, results will be labelled with the audio\n" |
99 " sample frame at which they occur. Otherwise, they will be labelled\n" | 111 " sample frame at which they occur. Otherwise, they will be labelled\n" |
100 " with time in seconds.\n\n" | 112 " with time in seconds.\n\n" |
101 " " << name << " -l\n\n" | 113 " " << name << " -l\n" |
114 " " << name << " --list\n\n" | |
102 " -- List the plugin libraries and Vamp plugins in the library search path\n" | 115 " -- List the plugin libraries and Vamp plugins in the library search path\n" |
103 " in a verbose human-readable format.\n\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" | |
104 " " << name << " --list-ids\n\n" | 120 " " << name << " --list-ids\n\n" |
105 " -- List the plugins in the search path in a terse machine-readable format,\n" | 121 " -- List the plugins in the search path in a terse machine-readable format,\n" |
106 " in the form vamp:soname:identifier.\n\n" | 122 " in the form vamp:soname:identifier.\n\n" |
107 " " << name << " --list-outputs\n\n" | 123 " " << name << " --list-outputs\n\n" |
108 " -- List the outputs for plugins in the search path in a machine-readable\n" | 124 " -- List the outputs for plugins in the search path in a machine-readable\n" |
137 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl | 153 cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl |
138 << "Vamp API version: " << VAMP_API_VERSION << endl | 154 << "Vamp API version: " << VAMP_API_VERSION << endl |
139 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; | 155 << "Vamp SDK version: " << VAMP_SDK_VERSION << endl; |
140 return 0; | 156 return 0; |
141 | 157 |
142 } else if (!strcmp(argv[1], "-l")) { | 158 } else if (!strcmp(argv[1], "-l") || !strcmp(argv[1], "--list")) { |
143 | 159 |
144 printPluginPath(true); | 160 printPluginPath(true); |
145 enumeratePlugins(PluginInformation); | 161 enumeratePlugins(PluginInformation); |
162 return 0; | |
163 | |
164 } else if (!strcmp(argv[1], "--list-full")) { | |
165 | |
166 enumeratePlugins(PluginInformationDetailed); | |
146 return 0; | 167 return 0; |
147 | 168 |
148 } else if (!strcmp(argv[1], "-p")) { | 169 } else if (!strcmp(argv[1], "-p")) { |
149 | 170 |
150 printPluginPath(false); | 171 printPluginPath(false); |
284 return 1; | 305 return 1; |
285 } | 306 } |
286 | 307 |
287 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; | 308 cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl; |
288 | 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 | |
289 int blockSize = plugin->getPreferredBlockSize(); | 321 int blockSize = plugin->getPreferredBlockSize(); |
290 int stepSize = plugin->getPreferredStepSize(); | 322 int stepSize = plugin->getPreferredStepSize(); |
291 | 323 |
292 if (blockSize == 0) { | 324 if (blockSize == 0) { |
293 blockSize = 1024; | 325 blockSize = 1024; |
315 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; | 347 for (int c = 0; c < channels; ++c) plugbuf[c] = new float[blockSize + 2]; |
316 | 348 |
317 cerr << "Using block size = " << blockSize << ", step size = " | 349 cerr << "Using block size = " << blockSize << ", step size = " |
318 << stepSize << endl; | 350 << stepSize << endl; |
319 | 351 |
352 // The channel queries here are for informational purposes only -- | |
353 // a PluginChannelAdapter is being used automatically behind the | |
354 // scenes, and it will take case of any channel mismatch | |
355 | |
320 int minch = plugin->getMinChannelCount(); | 356 int minch = plugin->getMinChannelCount(); |
321 int maxch = plugin->getMaxChannelCount(); | 357 int maxch = plugin->getMaxChannelCount(); |
322 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; | 358 cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl; |
323 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; | 359 cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl; |
324 | 360 |
369 goto done; | 405 goto done; |
370 } | 406 } |
371 | 407 |
372 wrapper = dynamic_cast<PluginWrapper *>(plugin); | 408 wrapper = dynamic_cast<PluginWrapper *>(plugin); |
373 if (wrapper) { | 409 if (wrapper) { |
410 // See documentation for | |
411 // PluginInputDomainAdapter::getTimestampAdjustment | |
374 PluginInputDomainAdapter *ida = | 412 PluginInputDomainAdapter *ida = |
375 wrapper->getWrapper<PluginInputDomainAdapter>(); | 413 wrapper->getWrapper<PluginInputDomainAdapter>(); |
376 if (ida) adjustment = ida->getTimestampAdjustment(); | 414 if (ida) adjustment = ida->getTimestampAdjustment(); |
377 } | 415 } |
378 | 416 |
503 } | 541 } |
504 | 542 |
505 if (verbose) cout << endl; | 543 if (verbose) cout << endl; |
506 } | 544 } |
507 | 545 |
546 static | |
547 string | |
548 header(string text, int level) | |
549 { | |
550 string out = '\n' + text + '\n'; | |
551 for (size_t i = 0; i < text.length(); ++i) { | |
552 out += (level == 1 ? '=' : level == 2 ? '-' : '~'); | |
553 } | |
554 out += '\n'; | |
555 return out; | |
556 } | |
557 | |
508 void | 558 void |
509 enumeratePlugins(Verbosity verbosity) | 559 enumeratePlugins(Verbosity verbosity) |
510 { | 560 { |
511 PluginLoader *loader = PluginLoader::getInstance(); | 561 PluginLoader *loader = PluginLoader::getInstance(); |
512 | 562 |
536 if (path != prevPath) { | 586 if (path != prevPath) { |
537 prevPath = path; | 587 prevPath = path; |
538 index = 0; | 588 index = 0; |
539 if (verbosity == PluginInformation) { | 589 if (verbosity == PluginInformation) { |
540 cout << "\n " << path << ":" << endl; | 590 cout << "\n " << path << ":" << endl; |
591 } else if (verbosity == PluginInformationDetailed) { | |
592 string::size_type ki = i->second.find(':'); | |
593 string text = "Library \"" + i->second.substr(0, ki) + "\""; | |
594 cout << "\n" << header(text, 1); | |
541 } | 595 } |
542 } | 596 } |
543 | 597 |
544 Plugin *plugin = loader->loadPlugin(key, 48000); | 598 Plugin *plugin = loader->loadPlugin(key, 48000); |
545 if (plugin) { | 599 if (plugin) { |
546 | 600 |
547 char c = char('A' + index); | 601 char c = char('A' + index); |
548 if (c > 'Z') c = char('a' + (index - 26)); | 602 if (c > 'Z') c = char('a' + (index - 26)); |
603 | |
604 PluginLoader::PluginCategoryHierarchy category = | |
605 loader->getPluginCategory(key); | |
606 string catstr; | |
607 if (!category.empty()) { | |
608 for (size_t ci = 0; ci < category.size(); ++ci) { | |
609 if (ci > 0) catstr += " > "; | |
610 catstr += category[ci]; | |
611 } | |
612 } | |
549 | 613 |
550 if (verbosity == PluginInformation) { | 614 if (verbosity == PluginInformation) { |
551 | 615 |
552 cout << " [" << c << "] [v" | 616 cout << " [" << c << "] [v" |
553 << plugin->getVampApiVersion() << "] " | 617 << plugin->getVampApiVersion() << "] " |
554 << plugin->getName() << ", \"" | 618 << plugin->getName() << ", \"" |
555 << plugin->getIdentifier() << "\"" << " [" | 619 << plugin->getIdentifier() << "\"" << " [" |
556 << plugin->getMaker() << "]" << endl; | 620 << plugin->getMaker() << "]" << endl; |
557 | 621 |
558 PluginLoader::PluginCategoryHierarchy category = | 622 if (catstr != "") { |
559 loader->getPluginCategory(key); | 623 cout << " > " << catstr << endl; |
560 | |
561 if (!category.empty()) { | |
562 cout << " "; | |
563 for (size_t ci = 0; ci < category.size(); ++ci) { | |
564 cout << " > " << category[ci]; | |
565 } | |
566 cout << endl; | |
567 } | 624 } |
568 | 625 |
569 if (plugin->getDescription() != "") { | 626 if (plugin->getDescription() != "") { |
570 cout << " - " << plugin->getDescription() << endl; | 627 cout << " - " << plugin->getDescription() << endl; |
571 } | 628 } |
572 | 629 |
630 } else if (verbosity == PluginInformationDetailed) { | |
631 | |
632 cout << header(plugin->getName(), 2); | |
633 cout << "- Identifier: " | |
634 << key << endl; | |
635 cout << "- Plugin Version: " | |
636 << plugin->getPluginVersion() << endl; | |
637 cout << "- Vamp API Version: " | |
638 << plugin->getVampApiVersion() << endl; | |
639 cout << "- Maker: \"" | |
640 << plugin->getMaker() << "\"" << endl; | |
641 cout << "- Copyright: \"" | |
642 << plugin->getCopyright() << "\"" << endl; | |
643 cout << "- Description: \"" | |
644 << plugin->getDescription() << "\"" << endl; | |
645 cout << "- Input Domain: " | |
646 << (plugin->getInputDomain() == Vamp::Plugin::TimeDomain ? | |
647 "Time Domain" : "Frequency Domain") << endl; | |
648 cout << "- Default Step Size: " | |
649 << plugin->getPreferredStepSize() << endl; | |
650 cout << "- Default Block Size: " | |
651 << plugin->getPreferredBlockSize() << endl; | |
652 cout << "- Minimum Channels: " | |
653 << plugin->getMinChannelCount() << endl; | |
654 cout << "- Maximum Channels: " | |
655 << plugin->getMaxChannelCount() << endl; | |
656 | |
573 } else if (verbosity == PluginIds) { | 657 } else if (verbosity == PluginIds) { |
574 cout << "vamp:" << key << endl; | 658 cout << "vamp:" << key << endl; |
575 } | 659 } |
576 | 660 |
577 Plugin::OutputList outputs = | 661 Plugin::OutputList outputs = |
578 plugin->getOutputDescriptors(); | 662 plugin->getOutputDescriptors(); |
663 | |
664 if (verbosity == PluginInformationDetailed) { | |
665 | |
666 Plugin::ParameterList params = plugin->getParameterDescriptors(); | |
667 for (size_t j = 0; j < params.size(); ++j) { | |
668 Plugin::ParameterDescriptor &pd(params[j]); | |
669 cout << "\nParameter " << j+1 << ": \"" << pd.name << "\"" << endl; | |
670 cout << "- Identifier: " << pd.identifier << endl; | |
671 cout << "- Description: \"" << pd.description << "\"" << endl; | |
672 if (pd.unit != "") { | |
673 cout << "- Unit: " << pd.unit << endl; | |
674 } | |
675 cout << "- Range: "; | |
676 cout << pd.minValue << " -> " << pd.maxValue << endl; | |
677 cout << "- Default: "; | |
678 cout << pd.defaultValue << endl; | |
679 if (pd.isQuantized) { | |
680 cout << "- Quantize Step: " | |
681 << pd.quantizeStep << endl; | |
682 } | |
683 if (!pd.valueNames.empty()) { | |
684 cout << "- Value Names: "; | |
685 for (size_t k = 0; k < pd.valueNames.size(); ++k) { | |
686 if (k > 0) cout << ", "; | |
687 cout << "\"" << pd.valueNames[k] << "\""; | |
688 } | |
689 cout << endl; | |
690 } | |
691 } | |
692 | |
693 if (outputs.empty()) { | |
694 cout << "\n** Note: This plugin reports no outputs!" << endl; | |
695 } | |
696 for (size_t j = 0; j < outputs.size(); ++j) { | |
697 Plugin::OutputDescriptor &od(outputs[j]); | |
698 cout << "\nOutput " << j+1 << ": \"" << od.name << "\"" << endl; | |
699 cout << "- Identifier: " << od.identifier << endl; | |
700 cout << "- Description: \"" << od.description << "\"" << endl; | |
701 if (od.unit != "") { | |
702 cout << "- Unit: " << od.unit << endl; | |
703 } | |
704 if (od.hasFixedBinCount) { | |
705 cout << "- Default Bin Count: " << od.binCount << endl; | |
706 } | |
707 if (!od.binNames.empty()) { | |
708 cout << "- Bin Names: "; | |
709 for (size_t k = 0; k < od.binNames.size(); ++k) { | |
710 if (k > 0) cout << ", "; | |
711 cout << "\"" << od.binNames[k] << "\""; | |
712 } | |
713 cout << endl; | |
714 } | |
715 if (od.hasKnownExtents) { | |
716 cout << "- Default Extents: "; | |
717 cout << od.minValue << " -> " << od.maxValue << endl; | |
718 } | |
719 if (od.isQuantized) { | |
720 cout << "- Quantize Step: " | |
721 << od.quantizeStep << endl; | |
722 } | |
723 cout << "- Sample Type: " | |
724 << (od.sampleType == | |
725 Plugin::OutputDescriptor::OneSamplePerStep ? | |
726 "One Sample Per Step" : | |
727 od.sampleType == | |
728 Plugin::OutputDescriptor::FixedSampleRate ? | |
729 "Fixed Sample Rate" : | |
730 "Variable Sample Rate") << endl; | |
731 if (od.sampleType != | |
732 Plugin::OutputDescriptor::OneSamplePerStep) { | |
733 cout << "- Default Rate: " | |
734 << od.sampleRate << endl; | |
735 } | |
736 cout << "- Has Duration: " | |
737 << (od.hasDuration ? "Yes" : "No") << endl; | |
738 } | |
739 } | |
579 | 740 |
580 if (outputs.size() > 1 || verbosity == PluginOutputIds) { | 741 if (outputs.size() > 1 || verbosity == PluginOutputIds) { |
581 for (size_t j = 0; j < outputs.size(); ++j) { | 742 for (size_t j = 0; j < outputs.size(); ++j) { |
582 if (verbosity == PluginInformation) { | 743 if (verbosity == PluginInformation) { |
583 cout << " (" << j << ") " | 744 cout << " (" << j << ") " |
597 | 758 |
598 delete plugin; | 759 delete plugin; |
599 } | 760 } |
600 } | 761 } |
601 | 762 |
602 if (verbosity == PluginInformation) { | 763 if (verbosity == PluginInformation || |
764 verbosity == PluginInformationDetailed) { | |
603 cout << endl; | 765 cout << endl; |
604 } | 766 } |
605 } | 767 } |
606 | 768 |
607 void | 769 void |