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