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