cannam@138: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@138: cannam@231: #include cannam@233: #include cannam@233: #include cannam@233: #include cannam@231: #include cannam@138: cannam@138: #include cannam@138: #include cannam@138: #include cannam@138: cannam@138: #include cannam@232: #include cannam@232: #include cannam@138: cannam@243: #include cannam@243: #include cannam@243: 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@217: //??? cannam@138: string programURI = "http://www.vamp-plugins.org/doap.rdf#template-generator"; cannam@138: cannam@138: void usage() cannam@138: { cannam@217: cerr << endl; cannam@251: cerr << "vamp-rdf-template-generator: Create a skeleton RDF description file describing" << endl; cannam@251: cerr << "a Vamp plugin library using the Vamp ontology." << endl; cannam@217: cerr << endl; cannam@217: cerr << "Usage:" << endl; cannam@251: cerr << " vamp-rdf-template-generator -i vamp:soname[:plugin] [vamp:soname[:plugin] ...]" << endl; cannam@251: cerr << " vamp-rdf-template-generator PLUGIN_BASE_URI [ -m YOUR_URI ] [vamp:]soname[:plugin] [[vamp:]soname[:plugin] ...]" << endl; cannam@217: cerr << endl; cannam@217: cerr << "Example:" << endl; cannam@251: cerr << " vamp-rdf-template-generator http://vamp-plugins.org/rdf/plugins/ vamp-example-plugins" << endl; cannam@217: cerr << 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@267: @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@217: "<> a vamp:PluginDescription ;\n"; cannam@217: if (describerURI != "") { cannam@217: res += " foaf:maker <"+describerURI+"> ;\n"; cannam@217: } cannam@217: res += "\ 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@218: res += " ; \n\ cannam@145: vamp:available_plugin plugbase:"+plugins[i]->getIdentifier(); cannam@144: } cannam@144: cannam@218: res += " ; \n\ cannam@218: # foaf:page ;\n\ cannam@218: .\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@221: dc:description \"\"\""+plugin->getDescription()+"\"\"\" ;\n\ cannam@154: foaf:maker [ foaf:name \""+plugin->getMaker()+"\" ] ; # FIXME could give plugin author's URI here\n\ cannam@224: dc:rights \"\"\""+plugin->getCopyright()+"\"\"\" ;\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@194: res+=" vamp:input_domain vamp:TimeDomain ;\n"; cannam@138: cannam@138: cannam@142: Plugin::ParameterList params = plugin->getParameterDescriptors(); cannam@194: if (!params.empty()) res+="\n"; 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@194: if (!params.empty()) 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@168: // SparseOutput: variable sample rate. Events are not evenly cannam@168: // spaced so we need to record the time associated with the event cannam@168: // as it its not ensured that we have an event after the next one cannam@168: // (but there is not time to set the duration, it has to be cannam@168: // calculated as the different between 2 different events). The cannam@168: // timestamp must be read. cannam@139: cannam@142: string res; cannam@139: cannam@168: if (o.sampleType == Plugin::OutputDescriptor::VariableSampleRate || cannam@168: !o.hasFixedBinCount) 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@273: 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@138: cannam@264: bool haveBinNames = false; cannam@264: for (int i=0; i < o.binNames.size(); i++) { cannam@264: if (o.binNames[i] != "") { cannam@264: haveBinNames = true; cannam@264: break; cannam@264: } cannam@264: } cannam@264: cannam@264: if (haveBinNames) { cannam@264: res+=" vamp:bin_names ("; cannam@264: cannam@264: unsigned int i; cannam@264: for (i=0; i+1 < o.binNames.size(); i++) cannam@264: res+=" \""+o.binNames[i]+"\""; cannam@264: if (i < o.binNames.size()) cannam@264: res+=" \""+o.binNames[i]+"\""; cannam@264: res+=");\n"; cannam@264: } 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@273: 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@139: cannam@264: bool haveBinNames = false; cannam@264: for (int i=0; i < o.binNames.size(); i++) { cannam@264: if (o.binNames[i] != "") { cannam@264: haveBinNames = true; cannam@264: break; cannam@264: } cannam@264: } cannam@264: cannam@264: if (haveBinNames) { cannam@264: res+=" vamp:bin_names ("; cannam@264: cannam@264: unsigned int i; cannam@264: for (i=0; i+1 < o.binNames.size(); i++) cannam@264: res+=" \""+o.binNames[i]+"\""; cannam@264: if (i < o.binNames.size()) cannam@264: res+=" \""+o.binNames[i]+"\""; cannam@264: res+=");\n"; cannam@264: } 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@217: if (!interactive && argc < 3) 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@217: if (!strcmp(argv[2], "-m")) { cannam@217: if (argc < 5) usage(); cannam@217: describerURI = argv[3]; cannam@217: argidx = 4; cannam@217: } cannam@144: } else { cannam@138: cerr << "Please enter the base URI for the plugin bundle : "; cannam@138: getline(cin, pluginBundleBaseURI); cannam@217: cerr << "Please enter your URI (empty to omit) : "; 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: