annotate rdf/generator/template-generator.cpp @ 194:27cfae2a4155

* Make summarising adapter debug optional * Tidy up template generator output a bit * Clarify an error message
author cannam
date Tue, 30 Sep 2008 13:24:41 +0000
parents 006a775133b1
children f9b4f60280db
rev   line source
cannam@138 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
cannam@138 2
cannam@138 3 #include "vamp-sdk/PluginHostAdapter.h"
cannam@138 4 #include "vamp-sdk/hostext/PluginChannelAdapter.h"
cannam@138 5 #include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
cannam@138 6 #include "vamp-sdk/hostext/PluginLoader.h"
cannam@138 7 #include "vamp/vamp.h"
cannam@138 8
cannam@138 9 #include <iostream>
cannam@138 10 #include <fstream>
cannam@138 11 #include <sstream>
cannam@138 12 #include <sndfile.h>
cannam@138 13
cannam@138 14 #include <cmath>
cannam@138 15
cannam@138 16 using std::cout;
cannam@138 17 using std::cin;
cannam@138 18 using std::cerr;
cannam@138 19 using std::getline;
cannam@138 20 using std::endl;
cannam@138 21 using std::string;
cannam@138 22 using std::vector;
cannam@138 23 using std::ofstream;
cannam@138 24 using std::ios;
cannam@138 25
cannam@138 26 using Vamp::HostExt::PluginLoader;
cannam@138 27 using Vamp::Plugin;
cannam@138 28
cannam@138 29 string programURI = "http://www.vamp-plugins.org/doap.rdf#template-generator";
cannam@138 30
cannam@138 31 void usage()
cannam@138 32 {
cannam@144 33 cerr << "usage: template-generator -i vamp:soname[:plugin] [vamp:soname[:plugin] ...]" << endl;
cannam@144 34 cerr << "usage: template-generator PLUGIN_BASE_URI YOUR_URI vamp:soname[:plugin] [vamp:soname[:plugin] ...]" << endl;
cannam@138 35 exit(2);
cannam@138 36 }
cannam@138 37
cannam@138 38 template <class T>
cannam@138 39 inline string to_string (const T& t)
cannam@138 40 {
cannam@138 41 std::stringstream ss;
cannam@138 42 ss << t;
cannam@138 43 return ss.str();
cannam@138 44 }
cannam@138 45
cannam@144 46 string describe_namespaces(string pluginBundleBaseURI, string libname)
cannam@138 47 {
cannam@142 48 string res=\
cannam@142 49 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n\
cannam@138 50 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .\n\
cannam@147 51 @prefix vamp: <http://purl.org/ontology/vamp/> .\n\
cannam@144 52 @prefix plugbase: <"+pluginBundleBaseURI+libname+"#> .\n\
cannam@138 53 @prefix owl: <http://www.w3.org/2002/07/owl#> .\n\
cannam@138 54 @prefix dc: <http://purl.org/dc/elements/1.1/> .\n\
cannam@138 55 @prefix af: <http://purl.org/ontology/af/> .\n\
cannam@138 56 @prefix foaf: <http://xmlns.com/foaf/0.1/> .\n\
cannam@138 57 @prefix cc: <http://web.resource.org/cc/> .\n\
cannam@138 58 @prefix : <> .\n\n";
cannam@138 59
cannam@142 60 return res;
cannam@138 61 }
cannam@138 62
cannam@144 63 string describe_doc(string describerURI, string pluginBundleBaseURI,
cannam@144 64 string libname)
cannam@138 65 {
cannam@142 66 string res=\
cannam@142 67 "<> a vamp:PluginDescription ;\n\
cannam@144 68 foaf:maker <"+describerURI+"> ;\n\
cannam@144 69 foaf:maker <"+programURI+"> ;\n\
cannam@144 70 foaf:primaryTopic <"+pluginBundleBaseURI+libname+"> .\n\n";
cannam@142 71 return res;
cannam@138 72 }
cannam@138 73
cannam@138 74
cannam@144 75 string describe_library(string libname, vector<Plugin *> plugins)
cannam@144 76 {
cannam@144 77 string res=\
cannam@144 78 ":"+libname+" a vamp:PluginLibrary ;\n\
cannam@144 79 vamp:identifier \""+libname+"\" ";
cannam@144 80
cannam@144 81 for (size_t i = 0; i < plugins.size(); ++i) {
cannam@144 82 res += "; \n\
cannam@145 83 vamp:available_plugin plugbase:"+plugins[i]->getIdentifier();
cannam@144 84 }
cannam@144 85
cannam@144 86 res += " .\n\n";
cannam@144 87 return res;
cannam@144 88 }
cannam@144 89
cannam@138 90 string describe_plugin(Plugin* plugin)
cannam@138 91 {
cannam@142 92 string res=\
cannam@142 93 "plugbase:"+plugin->getIdentifier()+" a vamp:Plugin ;\n\
cannam@138 94 dc:title \""+plugin->getName()+"\" ;\n\
cannam@139 95 vamp:name \""+plugin->getName()+"\" ;\n\
cannam@138 96 dc:description \""+plugin->getDescription()+"\" ;\n\
cannam@154 97 foaf:maker [ foaf:name \""+plugin->getMaker()+"\" ] ; # FIXME could give plugin author's URI here\n\
cannam@154 98 # cc:license <Place plugin license URI here and uncomment> ; \n\
cannam@138 99 vamp:identifier \""+plugin->getIdentifier()+"\" ;\n\
cannam@138 100 vamp:vamp_API_version vamp:api_version_"+to_string(plugin->getVampApiVersion())+" ;\n\
cannam@138 101 owl:versionInfo \""+to_string(plugin->getPluginVersion())+"\" ;\n";
cannam@142 102 if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain)
cannam@142 103 res+=" vamp:input_domain vamp:FrequencyDomain ;\n\n";
cannam@142 104 else
cannam@194 105 res+=" vamp:input_domain vamp:TimeDomain ;\n";
cannam@138 106
cannam@138 107
cannam@142 108 Plugin::ParameterList params = plugin->getParameterDescriptors();
cannam@194 109 if (!params.empty()) res+="\n";
cannam@142 110 for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++)
dpastor@156 111 res+=" vamp:parameter plugbase:"+plugin->getIdentifier()+"_param_"+(*i).identifier+" ;\n";
cannam@194 112 if (!params.empty()) res+="\n";
cannam@138 113
cannam@142 114 Plugin::OutputList outputs = plugin->getOutputDescriptors();
cannam@142 115 for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++)
cannam@158 116 res+=" vamp:output plugbase:"+plugin->getIdentifier()+"_output_"+(*i).identifier+" ;\n";
cannam@142 117 res+=" .\n";
cannam@138 118
cannam@142 119 return res;
cannam@138 120 }
cannam@138 121
cannam@144 122 string describe_param(Plugin *plugin, Plugin::ParameterDescriptor p)
cannam@138 123 {
cannam@148 124
cannam@148 125 //FIXME: dc:format and vamp:unit are the same???
dpastor@157 126 //Should be a QUantizedParameter also a Parameter??
cannam@148 127 if(p.isQuantized){
cannam@148 128 string res=\
dpastor@156 129 "plugbase:"+plugin->getIdentifier()+"_param_"+p.identifier+" a vamp:QuantizedParameter ;\n\
cannam@148 130 vamp:identifier \""+p.identifier+"\" ;\n\
cannam@148 131 dc:title \""+p.name+"\" ;\n\
cannam@148 132 dc:format \""+p.unit+"\" ;\n\
cannam@148 133 vamp:min_value "+to_string(p.minValue)+" ;\n\
cannam@148 134 vamp:max_value "+to_string(p.maxValue)+" ;\n\
cannam@148 135 vamp:unit \""+p.unit+"\" ;\n\
cannam@152 136 vamp:quantize_step "+to_string(p.quantizeStep)+" ;\n\
cannam@148 137 vamp:default_value "+to_string(p.defaultValue)+" ;\n\
cannam@148 138 vamp:value_names (";
cannam@148 139
cannam@148 140 unsigned int i;
cannam@148 141 for (i=0; i+1 < p.valueNames.size(); i++)
cannam@148 142 res+=" \""+p.valueNames[i]+"\"";
cannam@148 143 if (i < p.valueNames.size())
cannam@148 144 res+=" \""+p.valueNames[i]+"\"";
cannam@148 145 res+=");\n";
cannam@148 146
cannam@148 147 res+=" .\n";
cannam@148 148
cannam@148 149 return res;
cannam@148 150
cannam@148 151 }else{
cannam@142 152 string res=\
dpastor@156 153 "plugbase:"+plugin->getIdentifier()+"_param_"+p.identifier+" a vamp:Parameter ;\n\
cannam@138 154 vamp:identifier \""+p.identifier+"\" ;\n\
cannam@138 155 dc:title \""+p.name+"\" ;\n\
cannam@138 156 dc:format \""+p.unit+"\" ;\n\
cannam@139 157 vamp:min_value "+to_string(p.minValue)+" ;\n\
cannam@139 158 vamp:max_value "+to_string(p.maxValue)+" ;\n\
cannam@148 159 vamp:unit \""+p.unit+"\" ;\n\
cannam@148 160 vamp:default_value "+to_string(p.defaultValue)+" ;\n\
cannam@148 161 vamp:value_names (";
cannam@148 162
cannam@148 163 unsigned int i;
cannam@148 164 for (i=0; i+1 < p.valueNames.size(); i++)
cannam@148 165 res+=" \""+p.valueNames[i]+"\"";
cannam@148 166 if (i < p.valueNames.size())
cannam@148 167 res+=" \""+p.valueNames[i]+"\"";
cannam@148 168 res+=");\n";
cannam@148 169
cannam@148 170 res+=" .\n";
cannam@148 171
cannam@142 172 return res;
cannam@148 173
cannam@148 174 }
cannam@138 175 }
cannam@138 176
cannam@144 177 string describe_output(Plugin *plugin, Plugin::OutputDescriptor o)
cannam@138 178 {
cannam@138 179
cannam@142 180 //we need to distinguish here between different output types:
cannam@148 181
cannam@148 182 //Quantize or not
cannam@148 183 //KnownExtents or not
cannam@148 184 //Data output classification:
cannam@142 185 //DenseOutput
cannam@142 186 //SparseOutput
cannam@142 187 //TrackLevelOutput
cannam@139 188
cannam@139 189
cannam@168 190 // SparseOutput: variable sample rate. Events are not evenly
cannam@168 191 // spaced so we need to record the time associated with the event
cannam@168 192 // as it its not ensured that we have an event after the next one
cannam@168 193 // (but there is not time to set the duration, it has to be
cannam@168 194 // calculated as the different between 2 different events). The
cannam@168 195 // timestamp must be read.
cannam@139 196
cannam@142 197 string res;
cannam@139 198
cannam@168 199 if (o.sampleType == Plugin::OutputDescriptor::VariableSampleRate ||
cannam@168 200 !o.hasFixedBinCount)
cannam@142 201 {
cannam@139 202
cannam@142 203 res=\
cannam@144 204 "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:SparseOutput ;\n\
cannam@139 205 vamp:identifier \""+o.identifier+"\" ;\n\
cannam@139 206 dc:title \""+o.name+"\" ;\n\
cannam@139 207 dc:description \""+o.description+"\" ;\n\
cannam@139 208 vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\
cannam@139 209 vamp:unit \""+(o.unit)+"\" ;\n";
cannam@139 210
cannam@148 211
cannam@148 212 //another type of output
cannam@148 213 if(o.isQuantized){
cannam@148 214
cannam@148 215 res+=" a vamp:QuantizedOutput ;\n";
cannam@148 216 res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n";
cannam@148 217 }
cannam@148 218
cannam@148 219 //and yet another type
cannam@148 220 if(o.hasKnownExtents){
cannam@148 221
cannam@148 222 res+=" a vamp:KnownExtentsOutput ;\n";
cannam@148 223 res+=" vamp:min_value "+to_string(o.minValue)+" ;\n";
cannam@148 224 res+=" vamp:max_value "+to_string(o.maxValue)+" ;\n";
cannam@148 225 }
cannam@139 226
cannam@142 227 // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading...
cannam@142 228 if (o.hasFixedBinCount)
cannam@142 229 {
cannam@144 230 res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n";
cannam@144 231 res+=" vamp:bin_names (";
cannam@138 232
cannam@142 233 unsigned int i;
cannam@142 234 for (i=0; i+1 < o.binNames.size(); i++)
cannam@142 235 res+=" \""+o.binNames[i]+"\"";
cannam@142 236 if (i < o.binNames.size())
cannam@142 237 res+=" \""+o.binNames[i]+"\"";
cannam@142 238 res+=");\n";
cannam@142 239 }
cannam@148 240
cannam@144 241 res+=" vamp:sample_type vamp:VariableSampleRate ;\n";
cannam@142 242 if (o.sampleRate > 0.0f)
cannam@144 243 res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n";
cannam@142 244
cannam@142 245 }
cannam@139 246
cannam@142 247 //If we do not have SparseOutput, then we have DenseOutput. TrackLevelOutput can not be inferred from the plugin directly without actually
cannam@142 248 //running the plugin.
cannam@142 249 else{
cannam@142 250
cannam@142 251 res=\
cannam@144 252 "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:DenseOutput ;\n\
cannam@139 253 vamp:identifier \""+o.identifier+"\" ;\n\
cannam@139 254 dc:title \""+o.name+"\" ;\n\
cannam@139 255 dc:description \""+o.description+"\" ;\n\
cannam@139 256 vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\
cannam@139 257 vamp:unit \""+(o.unit)+"\" ;\n";
cannam@139 258
cannam@139 259
cannam@148 260 //another type of output
cannam@148 261 if(o.isQuantized){
cannam@148 262
cannam@148 263 res+=" a vamp:QuantizedOutput ;\n";
cannam@148 264 res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n";
cannam@148 265 }
cannam@148 266
cannam@148 267 //and yet another type
cannam@148 268 if(o.hasKnownExtents){
cannam@148 269
cannam@148 270 res+=" a vamp:KnownExtentsOutput ;\n";
cannam@148 271 res+=" vamp:min_value "+to_string(o.minValue)+" ;\n";
cannam@148 272 res+=" vamp:max_value "+to_string(o.maxValue)+" ;\n";
cannam@148 273 }
cannam@139 274
cannam@142 275 // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading...
cannam@142 276 if (o.hasFixedBinCount)
cannam@142 277 {
cannam@144 278 res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n";
cannam@144 279 res+=" vamp:bin_names (";
cannam@139 280
cannam@142 281 unsigned int i;
cannam@142 282 for (i=0; i+1 < o.binNames.size(); i++)
cannam@142 283 res+=" \""+o.binNames[i]+"\"";
cannam@142 284 if (i < o.binNames.size())
cannam@142 285 res+=" \""+o.binNames[i]+"\"";
cannam@142 286 res+=");\n";
cannam@139 287 }
cannam@139 288
cannam@142 289 else if (o.sampleType == Plugin::OutputDescriptor::FixedSampleRate)
cannam@142 290 {
cannam@144 291 res+=" vamp:sample_type vamp:FixedSampleRate ;\n";
cannam@144 292 res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n";
cannam@142 293 }
cannam@142 294 else if (o.sampleType == Plugin::OutputDescriptor::OneSamplePerStep)
cannam@144 295 res+=" vamp:sample_type vamp:OneSamplePerStep ;\n";
cannam@142 296 else
cannam@142 297 {
cannam@142 298 cerr<<"Incomprehensible sampleType for output descriptor "+o.identifier<<" !"<<endl;
cannam@142 299 exit(1);
cannam@142 300 }
cannam@142 301 }
cannam@142 302
cannam@142 303 //There is no way to know this in advance, but we can use the km a bit for this.
cannam@159 304 res+="# vamp:computes_event_type <Place event type URI here and uncomment> ;\n";
cannam@159 305 res+="# vamp:computes_feature <Place feature attribute URI here and uncomment> ;\n";
cannam@159 306 res+="# vamp:computes_signal_type <Place signal type URI here and uncomment> ;\n";
cannam@142 307 res+=" .\n";
cannam@142 308
cannam@142 309 return res;
cannam@138 310 }
cannam@139 311
cannam@144 312 string describe(vector<Plugin *> plugins, string pluginBundleBaseURI,
cannam@144 313 string describerURI, string libname)
cannam@138 314 {
cannam@144 315 string res = describe_namespaces(pluginBundleBaseURI, libname);
cannam@138 316
cannam@144 317 res += describe_doc(describerURI, pluginBundleBaseURI, libname);
cannam@138 318
cannam@144 319 res += describe_library(libname, plugins);
cannam@144 320
cannam@144 321 for (size_t i = 0; i < plugins.size(); ++i) {
cannam@144 322
cannam@144 323 Plugin *plugin = plugins[i];
cannam@144 324
cannam@144 325 res += describe_plugin(plugin);
cannam@138 326
cannam@144 327 Plugin::ParameterList params = plugin->getParameterDescriptors();
cannam@144 328 for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++)
cannam@144 329 res += describe_param(plugin, *i);
cannam@138 330
cannam@144 331 Plugin::OutputList outputs = plugin->getOutputDescriptors();
cannam@144 332 for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++)
cannam@144 333 res += describe_output(plugin, *i);
cannam@144 334 }
cannam@138 335
cannam@142 336 return res;
cannam@138 337 }
cannam@138 338
cannam@138 339 int main(int argc, char **argv)
cannam@138 340 {
cannam@144 341 if (argc < 3) usage();
cannam@138 342
cannam@144 343 bool interactive = false;
cannam@144 344 if (!strcmp(argv[1], "-i")) interactive = true;
cannam@138 345
cannam@144 346 if (!interactive && argc < 4) usage();
cannam@138 347
cannam@138 348 string pluginBundleBaseURI, describerURI;
cannam@144 349
cannam@144 350 int argidx = 2;
cannam@138 351
cannam@144 352 if (!interactive) {
cannam@138 353 pluginBundleBaseURI = argv[1];
cannam@138 354 describerURI = argv[2];
cannam@144 355 argidx = 3;
cannam@144 356 } else {
cannam@138 357 cerr << "Please enter the base URI for the plugin bundle : ";
cannam@138 358 getline(cin, pluginBundleBaseURI);
cannam@138 359 cerr << "Please enter your URI : ";
cannam@138 360 getline(cin, describerURI);
cannam@138 361 }
cannam@144 362
cannam@144 363 vector<Plugin *> plugins;
cannam@144 364 string libname;
cannam@144 365
cannam@144 366 PluginLoader *loader = PluginLoader::getInstance();
cannam@144 367
cannam@144 368 while (argidx < argc) {
cannam@144 369
cannam@144 370 string pluginName = argv[argidx];
cannam@144 371
cannam@144 372 if (pluginName.substr(0, 5) == "vamp:") {
cannam@144 373 pluginName = pluginName.substr(5);
cannam@144 374 }
cannam@144 375
cannam@144 376 string mylibname = pluginName.substr(0, pluginName.find(':'));
cannam@144 377
cannam@144 378 if (libname == "") libname = mylibname;
cannam@144 379 else if (libname != mylibname) {
cannam@144 380 cerr << "ERROR: All plugins specified on command line must originate in the same library" << endl;
cannam@144 381 exit(1);
cannam@144 382 }
cannam@144 383
cannam@144 384 if (mylibname == pluginName) { // pluginName is a library, not a plugin
cannam@144 385
cannam@144 386 PluginLoader::PluginKeyList list = loader->listPlugins();
cannam@144 387 for (size_t i = 0; i < list.size(); ++i) {
cannam@144 388 string thislibname = list[i].substr(0, list[i].find(':'));
cannam@144 389 if (thislibname != mylibname) continue;
cannam@144 390 Plugin *plugin = loader->loadPlugin(list[i], 44100);
cannam@144 391 if (!plugin) {
cannam@144 392 cerr << "ERROR: Plugin \"" << list[i] << "\" could not be loaded" << endl;
cannam@144 393 exit(1);
cannam@144 394 }
cannam@144 395 plugins.push_back(plugin);
cannam@144 396 }
cannam@151 397
cannam@151 398 if (plugins.empty()) {
cannam@151 399 cerr << "ERROR: Plugin library \"" << mylibname << "\" does not exist, could not be opened, or contains no plugins" << endl;
cannam@151 400 exit(1);
cannam@151 401 }
cannam@151 402
cannam@144 403 } else { // pluginName is a plugin
cannam@144 404
cannam@144 405 Plugin *plugin = loader->loadPlugin(pluginName, size_t(44100));
cannam@144 406 if (!plugin) {
cannam@144 407 cerr << "ERROR: Plugin \"" << pluginName << "\" could not be loaded" << endl;
cannam@144 408 exit(1);
cannam@144 409 }
cannam@144 410 plugins.push_back(plugin);
cannam@144 411 }
cannam@144 412
cannam@144 413 ++argidx;
cannam@144 414 }
cannam@138 415
cannam@144 416 cout << describe(plugins, pluginBundleBaseURI, describerURI, libname) << endl;
cannam@138 417
cannam@138 418 return 0;
cannam@138 419 }
cannam@138 420
cannam@138 421