cannam@138: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@138: cannam@138: #include "vamp-sdk/PluginHostAdapter.h" cannam@138: #include "vamp-sdk/hostext/PluginChannelAdapter.h" cannam@138: #include "vamp-sdk/hostext/PluginInputDomainAdapter.h" cannam@138: #include "vamp-sdk/hostext/PluginLoader.h" cannam@138: #include "vamp/vamp.h" cannam@138: cannam@138: #include cannam@138: #include cannam@138: #include cannam@138: #include cannam@138: cannam@138: #include cannam@138: cannam@138: using std::cout; cannam@138: using std::cin; cannam@138: using std::cerr; cannam@138: using std::getline; cannam@138: using std::endl; cannam@138: using std::string; cannam@138: using std::vector; cannam@138: using std::ofstream; cannam@138: using std::ios; cannam@138: cannam@138: using Vamp::HostExt::PluginLoader; cannam@138: using Vamp::Plugin; cannam@138: cannam@138: string programURI = "http://www.vamp-plugins.org/doap.rdf#template-generator"; cannam@138: cannam@138: void usage() cannam@138: { cannam@144: cerr << "usage: template-generator -i vamp:soname[:plugin] [vamp:soname[:plugin] ...]" << endl; cannam@144: cerr << "usage: template-generator PLUGIN_BASE_URI YOUR_URI vamp:soname[:plugin] [vamp:soname[:plugin] ...]" << endl; cannam@138: exit(2); cannam@138: } cannam@138: cannam@138: template cannam@138: inline string to_string (const T& t) cannam@138: { cannam@138: std::stringstream ss; cannam@138: ss << t; cannam@138: return ss.str(); cannam@138: } cannam@138: cannam@144: string describe_namespaces(string pluginBundleBaseURI, string libname) cannam@138: { cannam@142: string res=\ cannam@142: "@prefix rdfs: .\n\ cannam@138: @prefix xsd: .\n\ cannam@147: @prefix vamp: .\n\ cannam@144: @prefix plugbase: <"+pluginBundleBaseURI+libname+"#> .\n\ cannam@138: @prefix owl: .\n\ cannam@138: @prefix dc: .\n\ cannam@138: @prefix af: .\n\ cannam@138: @prefix foaf: .\n\ cannam@138: @prefix cc: .\n\ cannam@138: @prefix : <> .\n\n"; cannam@138: cannam@142: return res; cannam@138: } cannam@138: cannam@144: string describe_doc(string describerURI, string pluginBundleBaseURI, cannam@144: string libname) cannam@138: { cannam@142: string res=\ cannam@142: "<> a vamp:PluginDescription ;\n\ cannam@144: foaf:maker <"+describerURI+"> ;\n\ cannam@144: foaf:maker <"+programURI+"> ;\n\ cannam@144: foaf:primaryTopic <"+pluginBundleBaseURI+libname+"> .\n\n"; cannam@142: return res; cannam@138: } cannam@138: cannam@138: cannam@144: string describe_library(string libname, vector plugins) cannam@144: { cannam@144: string res=\ cannam@144: ":"+libname+" a vamp:PluginLibrary ;\n\ cannam@144: vamp:identifier \""+libname+"\" "; cannam@144: cannam@144: for (size_t i = 0; i < plugins.size(); ++i) { cannam@144: res += "; \n\ cannam@145: vamp:available_plugin plugbase:"+plugins[i]->getIdentifier(); cannam@144: } cannam@144: cannam@144: res += " .\n\n"; cannam@144: return res; cannam@144: } cannam@144: cannam@138: string describe_plugin(Plugin* plugin) cannam@138: { cannam@142: string res=\ cannam@142: "plugbase:"+plugin->getIdentifier()+" a vamp:Plugin ;\n\ cannam@138: dc:title \""+plugin->getName()+"\" ;\n\ cannam@139: vamp:name \""+plugin->getName()+"\" ;\n\ cannam@138: dc:description \""+plugin->getDescription()+"\" ;\n\ cannam@154: foaf:maker [ foaf:name \""+plugin->getMaker()+"\" ] ; # FIXME could give plugin author's URI here\n\ cannam@154: # cc:license ; \n\ cannam@138: vamp:identifier \""+plugin->getIdentifier()+"\" ;\n\ cannam@138: vamp:vamp_API_version vamp:api_version_"+to_string(plugin->getVampApiVersion())+" ;\n\ cannam@138: owl:versionInfo \""+to_string(plugin->getPluginVersion())+"\" ;\n"; cannam@142: if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) cannam@142: res+=" vamp:input_domain vamp:FrequencyDomain ;\n\n"; cannam@142: else cannam@142: res+=" vamp:input_domain vamp:TimeDomain ;\n\n"; cannam@138: cannam@138: cannam@142: Plugin::ParameterList params = plugin->getParameterDescriptors(); cannam@142: for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++) dpastor@156: res+=" vamp:parameter plugbase:"+plugin->getIdentifier()+"_param_"+(*i).identifier+" ;\n"; cannam@142: res+="\n"; cannam@138: cannam@142: Plugin::OutputList outputs = plugin->getOutputDescriptors(); cannam@142: for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++) cannam@158: res+=" vamp:output plugbase:"+plugin->getIdentifier()+"_output_"+(*i).identifier+" ;\n"; cannam@142: res+=" .\n"; cannam@138: cannam@142: return res; cannam@138: } cannam@138: cannam@144: string describe_param(Plugin *plugin, Plugin::ParameterDescriptor p) cannam@138: { cannam@148: cannam@148: //FIXME: dc:format and vamp:unit are the same??? dpastor@157: //Should be a QUantizedParameter also a Parameter?? cannam@148: if(p.isQuantized){ cannam@148: string res=\ dpastor@156: "plugbase:"+plugin->getIdentifier()+"_param_"+p.identifier+" a vamp:QuantizedParameter ;\n\ cannam@148: vamp:identifier \""+p.identifier+"\" ;\n\ cannam@148: dc:title \""+p.name+"\" ;\n\ cannam@148: dc:format \""+p.unit+"\" ;\n\ cannam@148: vamp:min_value "+to_string(p.minValue)+" ;\n\ cannam@148: vamp:max_value "+to_string(p.maxValue)+" ;\n\ cannam@148: vamp:unit \""+p.unit+"\" ;\n\ cannam@152: vamp:quantize_step "+to_string(p.quantizeStep)+" ;\n\ cannam@148: vamp:default_value "+to_string(p.defaultValue)+" ;\n\ cannam@148: vamp:value_names ("; cannam@148: cannam@148: unsigned int i; cannam@148: for (i=0; i+1 < p.valueNames.size(); i++) cannam@148: res+=" \""+p.valueNames[i]+"\""; cannam@148: if (i < p.valueNames.size()) cannam@148: res+=" \""+p.valueNames[i]+"\""; cannam@148: res+=");\n"; cannam@148: cannam@148: res+=" .\n"; cannam@148: cannam@148: return res; cannam@148: cannam@148: }else{ cannam@142: string res=\ dpastor@156: "plugbase:"+plugin->getIdentifier()+"_param_"+p.identifier+" a vamp:Parameter ;\n\ cannam@138: vamp:identifier \""+p.identifier+"\" ;\n\ cannam@138: dc:title \""+p.name+"\" ;\n\ cannam@138: dc:format \""+p.unit+"\" ;\n\ cannam@139: vamp:min_value "+to_string(p.minValue)+" ;\n\ cannam@139: vamp:max_value "+to_string(p.maxValue)+" ;\n\ cannam@148: vamp:unit \""+p.unit+"\" ;\n\ cannam@148: vamp:default_value "+to_string(p.defaultValue)+" ;\n\ cannam@148: vamp:value_names ("; cannam@148: cannam@148: unsigned int i; cannam@148: for (i=0; i+1 < p.valueNames.size(); i++) cannam@148: res+=" \""+p.valueNames[i]+"\""; cannam@148: if (i < p.valueNames.size()) cannam@148: res+=" \""+p.valueNames[i]+"\""; cannam@148: res+=");\n"; cannam@148: cannam@148: res+=" .\n"; cannam@148: cannam@142: return res; cannam@148: cannam@148: } cannam@138: } cannam@138: cannam@144: string describe_output(Plugin *plugin, Plugin::OutputDescriptor o) cannam@138: { cannam@138: cannam@142: //we need to distinguish here between different output types: cannam@148: cannam@148: //Quantize or not cannam@148: //KnownExtents or not cannam@148: //Data output classification: cannam@142: //DenseOutput cannam@142: //SparseOutput cannam@142: //TrackLevelOutput cannam@139: cannam@139: cannam@142: //SparseOutput: variable sample rate. Events are not evenly spaced so we need to record the time associated with the event as it its not ensured that we have an event after the next one (but there is not time to set the duration, it has to be calculated as the different between 2 different events). The timestamp must be read. cannam@139: cannam@142: string res; cannam@139: cannam@142: if (o.sampleType == Plugin::OutputDescriptor::VariableSampleRate) cannam@142: { cannam@139: cannam@142: res=\ cannam@144: "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:SparseOutput ;\n\ cannam@139: vamp:identifier \""+o.identifier+"\" ;\n\ cannam@139: dc:title \""+o.name+"\" ;\n\ cannam@139: dc:description \""+o.description+"\" ;\n\ cannam@139: vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\ cannam@139: vamp:unit \""+(o.unit)+"\" ;\n"; cannam@139: cannam@148: cannam@148: //another type of output cannam@148: if(o.isQuantized){ cannam@148: cannam@148: res+=" a vamp:QuantizedOutput ;\n"; cannam@148: res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n"; cannam@148: } cannam@148: cannam@148: //and yet another type cannam@148: if(o.hasKnownExtents){ cannam@148: cannam@148: res+=" a vamp:KnownExtentsOutput ;\n"; cannam@148: res+=" vamp:min_value "+to_string(o.minValue)+" ;\n"; cannam@148: res+=" vamp:max_value "+to_string(o.maxValue)+" ;\n"; cannam@148: } cannam@139: cannam@142: // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading... cannam@142: if (o.hasFixedBinCount) cannam@142: { cannam@144: res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n"; cannam@144: res+=" vamp:bin_names ("; cannam@138: cannam@142: unsigned int i; cannam@142: for (i=0; i+1 < o.binNames.size(); i++) cannam@142: res+=" \""+o.binNames[i]+"\""; cannam@142: if (i < o.binNames.size()) cannam@142: res+=" \""+o.binNames[i]+"\""; cannam@142: res+=");\n"; cannam@142: } cannam@148: cannam@144: res+=" vamp:sample_type vamp:VariableSampleRate ;\n"; cannam@142: if (o.sampleRate > 0.0f) cannam@144: res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n"; cannam@142: cannam@142: } cannam@139: cannam@142: //If we do not have SparseOutput, then we have DenseOutput. TrackLevelOutput can not be inferred from the plugin directly without actually cannam@142: //running the plugin. cannam@142: else{ cannam@142: cannam@142: res=\ cannam@144: "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:DenseOutput ;\n\ cannam@139: vamp:identifier \""+o.identifier+"\" ;\n\ cannam@139: dc:title \""+o.name+"\" ;\n\ cannam@139: dc:description \""+o.description+"\" ;\n\ cannam@139: vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\ cannam@139: vamp:unit \""+(o.unit)+"\" ;\n"; cannam@139: cannam@139: cannam@148: //another type of output cannam@148: if(o.isQuantized){ cannam@148: cannam@148: res+=" a vamp:QuantizedOutput ;\n"; cannam@148: res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n"; cannam@148: } cannam@148: cannam@148: //and yet another type cannam@148: if(o.hasKnownExtents){ cannam@148: cannam@148: res+=" a vamp:KnownExtentsOutput ;\n"; cannam@148: res+=" vamp:min_value "+to_string(o.minValue)+" ;\n"; cannam@148: res+=" vamp:max_value "+to_string(o.maxValue)+" ;\n"; cannam@148: } cannam@139: cannam@142: // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading... cannam@142: if (o.hasFixedBinCount) cannam@142: { cannam@144: res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n"; cannam@144: res+=" vamp:bin_names ("; cannam@139: cannam@142: unsigned int i; cannam@142: for (i=0; i+1 < o.binNames.size(); i++) cannam@142: res+=" \""+o.binNames[i]+"\""; cannam@142: if (i < o.binNames.size()) cannam@142: res+=" \""+o.binNames[i]+"\""; cannam@142: res+=");\n"; cannam@139: } cannam@139: cannam@142: else if (o.sampleType == Plugin::OutputDescriptor::FixedSampleRate) cannam@142: { cannam@144: res+=" vamp:sample_type vamp:FixedSampleRate ;\n"; cannam@144: res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n"; cannam@142: } cannam@142: else if (o.sampleType == Plugin::OutputDescriptor::OneSamplePerStep) cannam@144: res+=" vamp:sample_type vamp:OneSamplePerStep ;\n"; cannam@142: else cannam@142: { cannam@142: cerr<<"Incomprehensible sampleType for output descriptor "+o.identifier<<" !"< plugins, string pluginBundleBaseURI, cannam@144: string describerURI, string libname) cannam@138: { cannam@144: string res = describe_namespaces(pluginBundleBaseURI, libname); cannam@138: cannam@144: res += describe_doc(describerURI, pluginBundleBaseURI, libname); cannam@138: cannam@144: res += describe_library(libname, plugins); cannam@144: cannam@144: for (size_t i = 0; i < plugins.size(); ++i) { cannam@144: cannam@144: Plugin *plugin = plugins[i]; cannam@144: cannam@144: res += describe_plugin(plugin); cannam@138: cannam@144: Plugin::ParameterList params = plugin->getParameterDescriptors(); cannam@144: for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++) cannam@144: res += describe_param(plugin, *i); cannam@138: cannam@144: Plugin::OutputList outputs = plugin->getOutputDescriptors(); cannam@144: for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++) cannam@144: res += describe_output(plugin, *i); cannam@144: } cannam@138: cannam@142: return res; cannam@138: } cannam@138: cannam@138: int main(int argc, char **argv) cannam@138: { cannam@144: if (argc < 3) usage(); cannam@138: cannam@144: bool interactive = false; cannam@144: if (!strcmp(argv[1], "-i")) interactive = true; cannam@138: cannam@144: if (!interactive && argc < 4) usage(); cannam@138: cannam@138: string pluginBundleBaseURI, describerURI; cannam@144: cannam@144: int argidx = 2; cannam@138: cannam@144: if (!interactive) { cannam@138: pluginBundleBaseURI = argv[1]; cannam@138: describerURI = argv[2]; cannam@144: argidx = 3; cannam@144: } else { cannam@138: cerr << "Please enter the base URI for the plugin bundle : "; cannam@138: getline(cin, pluginBundleBaseURI); cannam@138: cerr << "Please enter your URI : "; cannam@138: getline(cin, describerURI); cannam@138: } cannam@144: cannam@144: vector plugins; cannam@144: string libname; cannam@144: cannam@144: PluginLoader *loader = PluginLoader::getInstance(); cannam@144: cannam@144: while (argidx < argc) { cannam@144: cannam@144: string pluginName = argv[argidx]; cannam@144: cannam@144: if (pluginName.substr(0, 5) == "vamp:") { cannam@144: pluginName = pluginName.substr(5); cannam@144: } cannam@144: cannam@144: string mylibname = pluginName.substr(0, pluginName.find(':')); cannam@144: cannam@144: if (libname == "") libname = mylibname; cannam@144: else if (libname != mylibname) { cannam@144: cerr << "ERROR: All plugins specified on command line must originate in the same library" << endl; cannam@144: exit(1); cannam@144: } cannam@144: cannam@144: if (mylibname == pluginName) { // pluginName is a library, not a plugin cannam@144: cannam@144: PluginLoader::PluginKeyList list = loader->listPlugins(); cannam@144: for (size_t i = 0; i < list.size(); ++i) { cannam@144: string thislibname = list[i].substr(0, list[i].find(':')); cannam@144: if (thislibname != mylibname) continue; cannam@144: Plugin *plugin = loader->loadPlugin(list[i], 44100); cannam@144: if (!plugin) { cannam@144: cerr << "ERROR: Plugin \"" << list[i] << "\" could not be loaded" << endl; cannam@144: exit(1); cannam@144: } cannam@144: plugins.push_back(plugin); cannam@144: } cannam@151: cannam@151: if (plugins.empty()) { cannam@151: cerr << "ERROR: Plugin library \"" << mylibname << "\" does not exist, could not be opened, or contains no plugins" << endl; cannam@151: exit(1); cannam@151: } cannam@151: cannam@144: } else { // pluginName is a plugin cannam@144: cannam@144: Plugin *plugin = loader->loadPlugin(pluginName, size_t(44100)); cannam@144: if (!plugin) { cannam@144: cerr << "ERROR: Plugin \"" << pluginName << "\" could not be loaded" << endl; cannam@144: exit(1); cannam@144: } cannam@144: plugins.push_back(plugin); cannam@144: } cannam@144: cannam@144: ++argidx; cannam@144: } cannam@138: cannam@144: cout << describe(plugins, pluginBundleBaseURI, describerURI, libname) << endl; cannam@138: cannam@138: return 0; cannam@138: } cannam@138: cannam@138: