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