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