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@139
|
51 @prefix vamp: <http://www.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@138
|
97 foaf:maker [ foaf:name \""+plugin->getMaker()+"\"] ; # FIXME could give plugin author's URI here\n\
|
cannam@138
|
98 cc:license <FIXME license for the plugin> ; \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@142
|
105 res+=" vamp:input_domain vamp:TimeDomain ;\n\n";
|
cannam@138
|
106
|
cannam@138
|
107
|
cannam@142
|
108 Plugin::ParameterList params = plugin->getParameterDescriptors();
|
cannam@142
|
109 for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++)
|
cannam@144
|
110 res+=" vamp:parameter_descriptor plugbase:"+plugin->getIdentifier()+"_param_"+(*i).identifier+" ;\n";
|
cannam@142
|
111 res+="\n";
|
cannam@138
|
112
|
cannam@142
|
113 Plugin::OutputList outputs = plugin->getOutputDescriptors();
|
cannam@142
|
114 for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++)
|
cannam@144
|
115 res+=" vamp:output_descriptor plugbase:"+plugin->getIdentifier()+"_output_"+(*i).identifier+" ;\n";
|
cannam@142
|
116 res+=" .\n";
|
cannam@138
|
117
|
cannam@142
|
118 return res;
|
cannam@138
|
119 }
|
cannam@138
|
120
|
cannam@144
|
121 string describe_param(Plugin *plugin, Plugin::ParameterDescriptor p)
|
cannam@138
|
122 {
|
cannam@142
|
123 string res=\
|
cannam@144
|
124 "plugbase:"+plugin->getIdentifier()+"_param_"+p.identifier+" a vamp:ParameterDescriptor ;\n\
|
cannam@138
|
125 vamp:identifier \""+p.identifier+"\" ;\n\
|
cannam@138
|
126 dc:title \""+p.name+"\" ;\n\
|
cannam@138
|
127 dc:format \""+p.unit+"\" ;\n\
|
cannam@139
|
128 vamp:min_value "+to_string(p.minValue)+" ;\n\
|
cannam@139
|
129 vamp:max_value "+to_string(p.maxValue)+" ;\n\
|
cannam@139
|
130 vamp:default_value "+to_string(p.defaultValue)+" .\n\n";
|
cannam@142
|
131 return res;
|
cannam@138
|
132 }
|
cannam@138
|
133
|
cannam@144
|
134 string describe_output(Plugin *plugin, Plugin::OutputDescriptor o)
|
cannam@138
|
135 {
|
cannam@138
|
136
|
cannam@142
|
137 //we need to distinguish here between different output types:
|
cannam@142
|
138 //DenseOutput
|
cannam@142
|
139 //SparseOutput
|
cannam@142
|
140 //TrackLevelOutput
|
cannam@139
|
141
|
cannam@139
|
142
|
cannam@142
|
143 //SparseOutput: variable sample rate. Events are not evenly spaced so we need to record the time associated with the event as it its not ensured that we have an event after the next one (but there is not time to set the duration, it has to be calculated as the different between 2 different events). The timestamp must be read.
|
cannam@139
|
144
|
cannam@142
|
145 string res;
|
cannam@139
|
146
|
cannam@142
|
147 if (o.sampleType == Plugin::OutputDescriptor::VariableSampleRate)
|
cannam@142
|
148 {
|
cannam@139
|
149
|
cannam@142
|
150 res=\
|
cannam@144
|
151 "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:SparseOutput ;\n\
|
cannam@139
|
152 vamp:identifier \""+o.identifier+"\" ;\n\
|
cannam@139
|
153 dc:title \""+o.name+"\" ;\n\
|
cannam@139
|
154 dc:description \""+o.description+"\" ;\n\
|
cannam@139
|
155 vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\
|
cannam@139
|
156 vamp:is_quantized \""+(o.isQuantized == 1 ? "true" : "false")+"\" ;\n\
|
cannam@139
|
157 vamp:unit \""+(o.unit)+"\" ;\n";
|
cannam@139
|
158
|
cannam@139
|
159
|
cannam@139
|
160
|
cannam@142
|
161 // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading...
|
cannam@142
|
162 if (o.hasFixedBinCount)
|
cannam@142
|
163 {
|
cannam@144
|
164 res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n";
|
cannam@144
|
165 res+=" vamp:bin_names (";
|
cannam@138
|
166
|
cannam@142
|
167 unsigned int i;
|
cannam@142
|
168 for (i=0; i+1 < o.binNames.size(); i++)
|
cannam@142
|
169 res+=" \""+o.binNames[i]+"\"";
|
cannam@142
|
170 if (i < o.binNames.size())
|
cannam@142
|
171 res+=" \""+o.binNames[i]+"\"";
|
cannam@142
|
172 res+=");\n";
|
cannam@142
|
173 }
|
cannam@139
|
174
|
cannam@142
|
175 if (o.isQuantized)
|
cannam@142
|
176 {
|
cannam@144
|
177 res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n";
|
cannam@139
|
178 }
|
cannam@138
|
179
|
cannam@144
|
180 res+=" vamp:sample_type vamp:VariableSampleRate ;\n";
|
cannam@142
|
181 if (o.sampleRate > 0.0f)
|
cannam@144
|
182 res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n";
|
cannam@142
|
183
|
cannam@142
|
184 }
|
cannam@139
|
185
|
cannam@142
|
186 //If we do not have SparseOutput, then we have DenseOutput. TrackLevelOutput can not be inferred from the plugin directly without actually
|
cannam@142
|
187 //running the plugin.
|
cannam@142
|
188 else{
|
cannam@142
|
189
|
cannam@142
|
190 res=\
|
cannam@144
|
191 "plugbase:"+plugin->getIdentifier()+"_output_"+o.identifier+" a vamp:DenseOutput ;\n\
|
cannam@139
|
192 vamp:identifier \""+o.identifier+"\" ;\n\
|
cannam@139
|
193 dc:title \""+o.name+"\" ;\n\
|
cannam@139
|
194 dc:description \""+o.description+"\" ;\n\
|
cannam@139
|
195 vamp:fixed_bin_count \""+(o.hasFixedBinCount == 1 ? "true" : "false")+"\" ;\n\
|
cannam@139
|
196 vamp:is_quantised \""+(o.isQuantized == 1 ? "true" : "false")+"\" ;\n\
|
cannam@139
|
197 vamp:unit \""+(o.unit)+"\" ;\n";
|
cannam@139
|
198
|
cannam@139
|
199
|
cannam@139
|
200
|
cannam@142
|
201 // FIXME ? Bin names may vary based on plugin setup, so including them here might be misleading...
|
cannam@142
|
202 if (o.hasFixedBinCount)
|
cannam@142
|
203 {
|
cannam@144
|
204 res+=" vamp:bin_count "+to_string(o.binCount)+" ;\n";
|
cannam@144
|
205 res+=" vamp:bin_names (";
|
cannam@139
|
206
|
cannam@142
|
207 unsigned int i;
|
cannam@142
|
208 for (i=0; i+1 < o.binNames.size(); i++)
|
cannam@142
|
209 res+=" \""+o.binNames[i]+"\"";
|
cannam@142
|
210 if (i < o.binNames.size())
|
cannam@142
|
211 res+=" \""+o.binNames[i]+"\"";
|
cannam@142
|
212 res+=");\n";
|
cannam@139
|
213 }
|
cannam@139
|
214
|
cannam@142
|
215 if (o.isQuantized)
|
cannam@142
|
216 {
|
cannam@144
|
217 res+=" vamp:quantize_step "+to_string(o.quantizeStep)+" ;\n";
|
cannam@142
|
218 }
|
cannam@138
|
219
|
cannam@142
|
220
|
cannam@142
|
221 else if (o.sampleType == Plugin::OutputDescriptor::FixedSampleRate)
|
cannam@142
|
222 {
|
cannam@144
|
223 res+=" vamp:sample_type vamp:FixedSampleRate ;\n";
|
cannam@144
|
224 res+=" vamp:sample_rate "+to_string(o.sampleRate)+" ;\n";
|
cannam@142
|
225 }
|
cannam@142
|
226 else if (o.sampleType == Plugin::OutputDescriptor::OneSamplePerStep)
|
cannam@144
|
227 res+=" vamp:sample_type vamp:OneSamplePerStep ;\n";
|
cannam@142
|
228 else
|
cannam@142
|
229 {
|
cannam@142
|
230 cerr<<"Incomprehensible sampleType for output descriptor "+o.identifier<<" !"<<endl;
|
cannam@142
|
231 exit(1);
|
cannam@142
|
232 }
|
cannam@142
|
233 }
|
cannam@142
|
234
|
cannam@142
|
235 //There is no way to know this in advance, but we can use the km a bit for this.
|
cannam@142
|
236 res+=" vamp:computes_feature_type <FIXME feature type URI> ;\n";
|
cannam@142
|
237 res+=" vamp:computes_event_type <FIXME event type URI> ;\n";
|
cannam@142
|
238 res+=" .\n";
|
cannam@142
|
239
|
cannam@142
|
240 return res;
|
cannam@138
|
241 }
|
cannam@139
|
242
|
cannam@144
|
243 string describe(vector<Plugin *> plugins, string pluginBundleBaseURI,
|
cannam@144
|
244 string describerURI, string libname)
|
cannam@138
|
245 {
|
cannam@144
|
246 string res = describe_namespaces(pluginBundleBaseURI, libname);
|
cannam@138
|
247
|
cannam@144
|
248 res += describe_doc(describerURI, pluginBundleBaseURI, libname);
|
cannam@138
|
249
|
cannam@144
|
250 res += describe_library(libname, plugins);
|
cannam@144
|
251
|
cannam@144
|
252 for (size_t i = 0; i < plugins.size(); ++i) {
|
cannam@144
|
253
|
cannam@144
|
254 Plugin *plugin = plugins[i];
|
cannam@144
|
255
|
cannam@144
|
256 res += describe_plugin(plugin);
|
cannam@138
|
257
|
cannam@144
|
258 Plugin::ParameterList params = plugin->getParameterDescriptors();
|
cannam@144
|
259 for (Plugin::ParameterList::const_iterator i = params.begin(); i != params.end(); i++)
|
cannam@144
|
260 res += describe_param(plugin, *i);
|
cannam@138
|
261
|
cannam@144
|
262 Plugin::OutputList outputs = plugin->getOutputDescriptors();
|
cannam@144
|
263 for (Plugin::OutputList::const_iterator i = outputs.begin(); i!= outputs.end(); i++)
|
cannam@144
|
264 res += describe_output(plugin, *i);
|
cannam@144
|
265 }
|
cannam@138
|
266
|
cannam@142
|
267 return res;
|
cannam@138
|
268 }
|
cannam@138
|
269
|
cannam@138
|
270 int main(int argc, char **argv)
|
cannam@138
|
271 {
|
cannam@144
|
272 if (argc < 3) usage();
|
cannam@138
|
273
|
cannam@144
|
274 bool interactive = false;
|
cannam@144
|
275 if (!strcmp(argv[1], "-i")) interactive = true;
|
cannam@138
|
276
|
cannam@144
|
277 if (!interactive && argc < 4) usage();
|
cannam@138
|
278
|
cannam@138
|
279 string pluginBundleBaseURI, describerURI;
|
cannam@144
|
280
|
cannam@144
|
281 int argidx = 2;
|
cannam@138
|
282
|
cannam@144
|
283 if (!interactive) {
|
cannam@138
|
284 pluginBundleBaseURI = argv[1];
|
cannam@138
|
285 describerURI = argv[2];
|
cannam@144
|
286 argidx = 3;
|
cannam@144
|
287 } else {
|
cannam@138
|
288 cerr << "Please enter the base URI for the plugin bundle : ";
|
cannam@138
|
289 getline(cin, pluginBundleBaseURI);
|
cannam@138
|
290 cerr << "Please enter your URI : ";
|
cannam@138
|
291 getline(cin, describerURI);
|
cannam@138
|
292 }
|
cannam@144
|
293
|
cannam@144
|
294 vector<Plugin *> plugins;
|
cannam@144
|
295 string libname;
|
cannam@144
|
296
|
cannam@144
|
297 PluginLoader *loader = PluginLoader::getInstance();
|
cannam@144
|
298
|
cannam@144
|
299 while (argidx < argc) {
|
cannam@144
|
300
|
cannam@144
|
301 string pluginName = argv[argidx];
|
cannam@144
|
302
|
cannam@144
|
303 if (pluginName.substr(0, 5) == "vamp:") {
|
cannam@144
|
304 pluginName = pluginName.substr(5);
|
cannam@144
|
305 }
|
cannam@144
|
306
|
cannam@144
|
307 string mylibname = pluginName.substr(0, pluginName.find(':'));
|
cannam@144
|
308
|
cannam@144
|
309 if (libname == "") libname = mylibname;
|
cannam@144
|
310 else if (libname != mylibname) {
|
cannam@144
|
311 cerr << "ERROR: All plugins specified on command line must originate in the same library" << endl;
|
cannam@144
|
312 exit(1);
|
cannam@144
|
313 }
|
cannam@144
|
314
|
cannam@144
|
315 if (mylibname == pluginName) { // pluginName is a library, not a plugin
|
cannam@144
|
316
|
cannam@144
|
317 PluginLoader::PluginKeyList list = loader->listPlugins();
|
cannam@144
|
318 for (size_t i = 0; i < list.size(); ++i) {
|
cannam@144
|
319 string thislibname = list[i].substr(0, list[i].find(':'));
|
cannam@144
|
320 if (thislibname != mylibname) continue;
|
cannam@144
|
321 Plugin *plugin = loader->loadPlugin(list[i], 44100);
|
cannam@144
|
322 if (!plugin) {
|
cannam@144
|
323 cerr << "ERROR: Plugin \"" << list[i] << "\" could not be loaded" << endl;
|
cannam@144
|
324 exit(1);
|
cannam@144
|
325 }
|
cannam@144
|
326 plugins.push_back(plugin);
|
cannam@144
|
327 }
|
cannam@144
|
328 } else { // pluginName is a plugin
|
cannam@144
|
329
|
cannam@144
|
330 Plugin *plugin = loader->loadPlugin(pluginName, size_t(44100));
|
cannam@144
|
331 if (!plugin) {
|
cannam@144
|
332 cerr << "ERROR: Plugin \"" << pluginName << "\" could not be loaded" << endl;
|
cannam@144
|
333 exit(1);
|
cannam@144
|
334 }
|
cannam@144
|
335 plugins.push_back(plugin);
|
cannam@144
|
336 }
|
cannam@144
|
337
|
cannam@144
|
338 ++argidx;
|
cannam@144
|
339 }
|
cannam@138
|
340
|
cannam@144
|
341 cout << describe(plugins, pluginBundleBaseURI, describerURI, libname) << endl;
|
cannam@138
|
342
|
cannam@138
|
343 return 0;
|
cannam@138
|
344 }
|
cannam@138
|
345
|
cannam@138
|
346
|