Vocoder: Separate order from amount of bands -> Isolation, remove unneccessary contro...
[calf.git] / src / makerdf.cpp
blobc9b4fc6bba6db4f2e95d6d201f4de618a6a77035
1 /* Calf DSP Library
2 * RDF file generator for LV2 plugins.
3 * Copyright (C) 2007-2011 Krzysztof Foltman and others.
4 * See AUTHORS file for a complete list.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General
17 * Public License along with this program; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301 USA
21 #include <calf/giface.h>
22 #include <calf/preset.h>
23 #include <calf/utils.h>
24 #if USE_LV2
25 #include <lv2.h>
26 #include <calf/lv2_event.h>
27 #include <calf/lv2_state.h>
28 #include <calf/lv2_uri_map.h>
29 #endif
30 #include <getopt.h>
31 #include <string.h>
32 #include <set>
34 using namespace std;
35 using namespace calf_utils;
36 using namespace calf_plugins;
38 static struct option long_options[] = {
39 {"help", 0, 0, 'h'},
40 {"version", 0, 0, 'v'},
41 {"mode", 1, 0, 'm'},
42 {"path", 1, 0, 'p'},
43 {0,0,0,0},
46 static FILE *open_and_check(const std::string &filename)
48 FILE *f = fopen(filename.c_str(), "w");
49 if (!f)
51 fprintf(stderr, "Cannot write file '%s': %s\n", filename.c_str(), strerror(errno));
52 exit(1);
54 return f;
57 #if USE_LV2
58 static void add_port(string &ports, const char *symbol, const char *name, const char *direction, int pidx, const char *type = "lv2:AudioPort", bool optional = false)
60 stringstream ss;
61 const char *ind = " ";
64 if (ports != "") ports += " , ";
65 ss << "[\n";
66 if (direction) ss << ind << "a lv2:" << direction << "Port ;\n";
67 ss << ind << "a " << type << " ;\n";
68 ss << ind << "lv2:index " << pidx << " ;\n";
69 ss << ind << "lv2:symbol \"" << symbol << "\" ;\n";
70 ss << ind << "lv2:name \"" << name << "\" ;\n";
71 if (optional)
72 ss << ind << "lv2:portProperty lv2:connectionOptional ;\n";
73 if (!strcmp(type, "lv2ev:EventPort")) {
74 ss << ind << "lv2ev:supportsEvent lv2midi:MidiEvent ;\n";
76 if (!strcmp(std::string(symbol, 0, 4).c_str(), "in_l"))
77 ss << ind << "lv2:designation pg:left ;\n"
78 << ind << "pg:group :in ;" << endl;
79 else
80 if (!strcmp(std::string(symbol, 0, 4).c_str(), "in_r"))
81 ss << ind << "lv2:designation pg:right ;\n"
82 << ind << "pg:group :in ;" << endl;
83 else
84 if (!strcmp(std::string(symbol, 0, 5).c_str(), "out_l"))
85 ss << ind << "lv2:designation pg:left ;\n"
86 << ind << "pg:group :out ;" << endl;
87 else
88 if (!strcmp(std::string(symbol, 0, 5).c_str(), "out_r"))
89 ss << ind << "lv2:designation pg:right ;\n"
90 << ind << "pg:group :out ;" << endl;
91 ss << " ]";
92 ports += ss.str();
95 static const char *units[] = {
96 "ue:db",
97 "ue:coef",
98 "ue:hz",
99 "ue:s",
100 "ue:ms",
101 "ue:cent",
102 "ue:semitone12TET",
103 "ue:bpm",
104 "ue:degree",
105 "ue:midiNote",
106 NULL // rotations per minute
109 //////////////// To all haters: calm down, I'll rewrite it to use the new interface one day
111 static bool add_ctl_port(string &ports, const parameter_properties &pp, int pidx, const plugin_metadata_iface *pmi, int param)
113 stringstream ss;
114 const char *ind = " ";
116 parameter_flags type = (parameter_flags)(pp.flags & PF_TYPEMASK);
117 uint8_t unit = (pp.flags & PF_UNITMASK) >> 24;
119 if (ports != "") ports += " , ";
120 ss << "[\n";
121 if (pp.flags & PF_PROP_OUTPUT)
122 ss << ind << "a lv2:OutputPort ;\n";
123 else
124 ss << ind << "a lv2:InputPort ;\n";
125 ss << ind << "a lv2:ControlPort ;\n";
126 ss << ind << "lv2:index " << pidx << " ;\n";
127 ss << ind << "lv2:symbol \"" << pp.short_name << "\" ;\n";
128 ss << ind << "lv2:name \"" << pp.name << "\" ;\n";
129 if ((pp.flags & PF_CTLMASK) == PF_CTL_BUTTON)
130 ss << ind << "lv2:portProperty epp:trigger ;\n";
131 if (!(pp.flags & PF_PROP_NOBOUNDS))
132 ss << ind << "lv2:portProperty epp:hasStrictBounds ;\n";
133 if (pp.flags & PF_PROP_EXPENSIVE)
134 ss << ind << "lv2:portProperty epp:expensive ;\n";
135 if (pp.flags & PF_PROP_OPTIONAL)
136 ss << ind << "lv2:portProperty lv2:connectionOptional ;\n";
137 if (pmi->is_noisy(param))
138 ss << ind << "lv2:portProperty epp:causesArtifacts ;\n";
139 if (!pmi->is_cv(param))
140 ss << ind << "lv2:portProperty epp:notAutomatic ;\n";
141 if (pp.flags & PF_PROP_OUTPUT_GAIN)
142 ss << ind << "lv2:designation param:gain ;\n";
143 if (type == PF_BOOL)
144 ss << ind << "lv2:portProperty lv2:toggled ;\n";
145 else if (type == PF_ENUM)
147 ss << ind << "lv2:portProperty lv2:integer ;\n";
148 ss << ind << "lv2:portProperty lv2:enumeration ;\n";
149 for (int i = (int)pp.min; i <= (int)pp.max; i++)
150 ss << ind << "lv2:scalePoint [ rdfs:label \"" << pp.choices[i - (int)pp.min] << "\"; rdf:value " << i <<" ] ;\n";
152 else if (type == PF_INT || type == PF_ENUM_MULTI)
153 ss << ind << "lv2:portProperty lv2:integer ;\n";
154 else if ((pp.flags & PF_SCALEMASK) == PF_SCALE_LOG)
155 ss << ind << "lv2:portProperty epp:logarithmic ;\n";
156 ss << showpoint;
157 if (!(pp.flags & PF_PROP_OUTPUT))
158 ss << ind << "lv2:default " << pp.def_value << " ;\n";
159 ss << ind << "lv2:minimum " << pp.min << " ;\n";
160 ss << ind << "lv2:maximum " << pp.max << " ;\n";
161 // XXX This value does not seem to match the definition of the property
162 //if (pp.step > 1)
163 // ss << ind << "epp:rangeSteps " << pp.step << " ;\n";
164 if (unit > 0 && unit < (sizeof(units) / sizeof(char *)) && units[unit - 1] != NULL)
165 ss << ind << "ue:unit " << units[unit - 1] << " ;\n";
167 // for now I assume that the only tempo passed is the tempo the plugin should operate with
168 // this may change as more complex plugins are added
170 if ((pp.flags & PF_SYNC_BPM))
171 ss << ind << "lv2:designation <http://lv2plug.in/ns/ext/time#beatsPerMinute> ;\n";
173 ss << " ]";
174 ports += ss.str();
175 return true;
178 void make_ttl(string path_prefix)
180 if (path_prefix.empty())
182 fprintf(stderr, "Path parameter is required for TTL mode\n");
183 exit(1);
185 string header;
187 header =
188 "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
189 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
190 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
191 "@prefix dct: <http://purl.org/dc/terms/> .\n"
192 "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
193 "@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> .\n"
194 "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .\n"
195 "@prefix lv2midi: <http://lv2plug.in/ns/ext/midi#> .\n"
196 "@prefix lv2ctx: <http://lv2plug.in/ns/dev/contexts#> .\n"
197 "@prefix strport: <http://lv2plug.in/ns/dev/string-port#> .\n"
198 "@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .\n"
199 "@prefix ue: <http://lv2plug.in/ns/extensions/units#> .\n"
200 "@prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n"
201 "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
202 "@prefix param: <http://lv2plug.in/ns/ext/parameters#> .\n"
204 "\n"
207 printf("Retrieving plugin list\n");
208 fflush(stdout);
209 const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
211 map<string, string> classes;
213 printf("Creating a list of plugin classes\n");
214 fflush(stdout);
215 const char *ptypes[] = {
216 "Flanger", "Reverb", "Generator", "Instrument", "Oscillator",
217 "Utility", "Converter", "Analyser", "Mixer", "Simulator",
218 "Delay", "Modulator", "Phaser", "Chorus", "Filter",
219 "Lowpass", "Highpass", "Bandpass", "Comb", "Allpass",
220 "Amplifier", "Distortion", "Waveshaper", "Dynamics", "Compressor",
221 "Expander", "Limiter", "Gate", "EQ", "ParaEQ", "MultiEQ", "Spatial",
222 "Spectral", "Pitch", "Envelope", "Function", "Constant",
223 NULL
226 for(const char **p = ptypes; *p; p++) {
227 string name = string(*p) + "Plugin";
228 classes[name] = "lv2:" + name;
230 classes["SynthesizerPlugin"] = "lv2:InstrumentPlugin";
232 string plugin_uri_prefix = "http://calf.sourceforge.net/plugins/";
234 string gui_header;
236 #if USE_LV2_GUI
237 string gtkgui_uri = "<http://calf.sourceforge.net/plugins/gui/gtk2-gui>";
238 gui_header = gtkgui_uri + "\n"
239 " a uiext:GtkUI ;\n"
240 " uiext:binary <calflv2gui.so> ;\n"
241 " uiext:requiredFeature uiext:makeResident .\n"
242 "\n"
244 #endif
246 map<string, pair<string, string> > id_to_info;
248 for (unsigned int i = 0; i < plugins.size(); i++) {
249 const plugin_metadata_iface *pi = plugins[i];
250 const ladspa_plugin_info &lpi = pi->get_plugin_info();
251 printf("Generating a .ttl file for plugin '%s'\n", lpi.label);
252 fflush(stdout);
253 string unquoted_uri = plugin_uri_prefix + string(lpi.label);
254 string uri = string("<" + unquoted_uri + ">");
255 id_to_info[pi->get_id()] = make_pair(lpi.label, uri);
256 string ttl;
257 ttl = "@prefix : <" + unquoted_uri + "#> .\n" + header + gui_header;
259 #if USE_LV2_GUI
260 for (int j = 0; j < pi->get_param_count(); j++)
262 const parameter_properties &props = *pi->get_param_props(j);
263 if (props.flags & PF_PROP_OUTPUT)
265 string portnot = " uiext:portNotification [\n uiext:plugin " + uri + " ;\n uiext:portIndex " + i2s(j) + "\n] .\n\n";
266 ttl += gtkgui_uri + portnot;
269 #endif
271 if(pi->get_input_count() == 1) {
272 ttl += ":in a pg:MonoGroup , pg:InputGroup ;\n"
273 " lv2:symbol \"in\" ;\n"
274 " rdfs:label \"Input\" .\n\n";
275 } else if(pi->get_input_count() >= 2) {
276 ttl += ":in a pg:StereoGroup , pg:InputGroup ;\n"
277 " lv2:symbol \"in\" ;\n"
278 " rdfs:label \"Input\" .\n\n";
280 if(pi->get_output_count() >= 2) {
281 ttl += ":out a pg:StereoGroup , pg:OutputGroup ;\n"
282 " lv2:symbol \"out\" ;\n"
283 " rdfs:label \"Output\" .\n\n";
286 ttl += uri + " a lv2:Plugin ;\n";
288 if (classes.count(lpi.plugin_type))
289 ttl += " a " + classes[lpi.plugin_type]+" ;\n";
292 ttl += " doap:name \""+string(lpi.name)+"\" ;\n";
293 ttl += " doap:maintainer [ foaf:name \""+string(lpi.maker)+"\" ; ] ;\n";
295 #if USE_LV2_GUI
296 ttl += " uiext:ui <http://calf.sourceforge.net/plugins/gui/gtk2-gui> ;\n";
297 ttl += " lv2:optionalFeature <http://lv2plug.in/ns/ext/instance-access> ;\n";
298 ttl += " lv2:optionalFeature <http://lv2plug.in/ns/ext/data-access> ;\n";
299 #endif
301 ttl += " doap:license <http://usefulinc.com/doap/licenses/lgpl> ;\n";
302 ttl += " dct:replaces <urn:ladspa:" + i2s(lpi.unique_id) + "> ;\n";
303 // XXXKF not really optional for now, to be honest
304 ttl += " lv2:optionalFeature epp:supportsStrictBounds ;\n";
305 if (pi->is_rt_capable())
306 ttl += " lv2:optionalFeature lv2:hardRTCapable ;\n";
307 if (pi->get_midi())
309 if (pi->requires_midi()) {
310 ttl += " lv2:requiredFeature <" LV2_URI_MAP_URI "> ;\n";
312 else {
313 ttl += " lv2:optionalFeature <" LV2_URI_MAP_URI "> ;\n";
317 vector<string> configure_keys;
318 pi->get_configure_vars(configure_keys);
319 if (!configure_keys.empty())
321 ttl += " lv2:extensionData <" LV2_STATE__interface "> ;\n";
324 if(pi->get_input_count() >= 1) {
325 ttl += " pg:mainInput :in ;\n";
327 if(pi->get_output_count() >= 2) {
328 ttl += " pg:mainOutput :out ;\n";
331 string ports = "";
332 int pn = 0;
333 const char *in_symbols[] = { "in_l", "in_r", "sidechain", "sidechain2" };
334 const char *in_names[] = { "In L", "In R", "Sidechain", "Sidechain 2" };
335 const char *out_symbols[] = { "out_l", "out_r", "out_l_2", "out_r_2", "out_l_3", "out_r_3", "out_l_4", "out_r_4" };
336 const char *out_names[] = { "Out L", "Out R", "Out L 2", "Out R 2", "Out L 3", "Out R 3", "Out L 4", "Out R 4" };
337 for (int i = 0; i < pi->get_input_count(); i++)
338 if(i <= pi->get_input_count() - pi->get_inputs_optional() - 1 && !(i == 1 && pi->get_simulate_stereo_input()))
339 add_port(ports, in_symbols[i], in_names[i], "Input", pn++);
340 else
341 add_port(ports, in_symbols[i], in_names[i], "Input", pn++, "lv2:AudioPort", true);
342 for (int i = 0; i < pi->get_output_count(); i++)
343 if(i <= pi->get_output_count() - pi->get_outputs_optional() - 1)
344 add_port(ports, out_symbols[i], out_names[i], "Output", pn++);
345 else
346 add_port(ports, out_symbols[i], out_names[i], "Output", pn++, "lv2:AudioPort", true);
347 for (int i = 0; i < pi->get_param_count(); i++)
348 if (add_ctl_port(ports, *pi->get_param_props(i), pn, pi, i))
349 pn++;
350 if (pi->get_midi()) {
351 add_port(ports, "event_in", "Event", "Input", pn++, "lv2ev:EventPort", true);
353 if (!ports.empty())
354 ttl += " lv2:port " + ports + "\n";
355 ttl += ".\n\n";
357 FILE *f = open_and_check(path_prefix+string(lpi.label)+".ttl");
358 fprintf(f, "%s\n", ttl.c_str());
359 fclose(f);
361 // Generate a manifest
362 printf("Writing presets\n");
363 fflush(stdout);
365 // Prefixes for the preset TTL
366 string presets_ttl_head =
367 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
368 "@prefix lv2p: <http://lv2plug.in/ns/ext/presets#> .\n"
369 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
370 "@prefix dct: <http://purl.org/dc/terms/> .\n"
371 "\n"
374 // Prefixes for the manifest TTL
375 string ttl = presets_ttl_head;
377 calf_plugins::get_builtin_presets().load_defaults(true);
378 calf_plugins::preset_vector &factory_presets = calf_plugins::get_builtin_presets().presets;
380 ttl += "\n";
382 // We'll collect TTL for presets here, maps plugin label to TTL generated so far
383 map<string, string> preset_data;
385 for (unsigned int i = 0; i < factory_presets.size(); i++)
387 plugin_preset &pr = factory_presets[i];
388 map<string, pair<string, string> >::iterator ilm = id_to_info.find(pr.plugin);
389 if (ilm == id_to_info.end())
390 continue;
392 string presets_ttl;
393 // if this is the first preset, add a header
394 if (!preset_data.count(ilm->second.first))
395 presets_ttl = presets_ttl_head;
397 string uri = "<http://calf.sourceforge.net/factory_presets#"
398 + pr.plugin + "_" + pr.get_safe_name()
399 + ">";
400 ttl += ilm->second.second + " lv2p:hasPreset\n " + uri + " .\n";
402 presets_ttl += uri +
403 " a lv2p:Preset ;\n"
404 " rdfs:label \"" + pr.name + "\" ;\n"
405 " lv2:appliesTo " + ilm->second.second + " ;\n"
406 " lv2:port \n"
409 unsigned int count = min(pr.param_names.size(), pr.values.size());
410 for (unsigned int j = 0; j < count; j++)
412 presets_ttl += " [ lv2:symbol \"" + pr.param_names[j] + "\" ; lv2p:value " + ff2s(pr.values[j]) + " ] ";
413 if (j < count - 1)
414 presets_ttl += ',';
415 presets_ttl += '\n';
417 presets_ttl += ".\n\n";
419 preset_data[ilm->second.first] += presets_ttl;
421 for (map<string, string>::iterator i = preset_data.begin(); i != preset_data.end(); i++)
423 FILE *f = open_and_check(path_prefix + "presets-" + i->first + ".ttl");
424 fprintf(f, "%s\n", i->second.c_str());
425 fclose(f);
428 printf("Generating a manifest file\n");
429 fflush(stdout);
430 for (unsigned int i = 0; i < plugins.size(); i++)
432 string label = plugins[i]->get_plugin_info().label;
433 ttl += string("<" + plugin_uri_prefix)
434 + string(plugins[i]->get_plugin_info().label)
435 + "> a lv2:Plugin ;\n dct:replaces <urn:ladspa:"
436 + i2s(plugins[i]->get_plugin_info().unique_id) + "> ;\n "
437 + "lv2:binary <calf.so> ; rdfs:seeAlso <" + label + ".ttl> ";
438 if (preset_data.count(label))
439 ttl += ", <presets-" + label + ".ttl>";
440 ttl += ".\n";
443 FILE *f = open_and_check(path_prefix+"manifest.ttl");
444 fprintf(f, "%s\n", ttl.c_str());
445 fclose(f);
449 #else
450 void make_ttl(string tmp)
452 fprintf(stderr, "LV2 not supported.\n");
455 #endif
457 void make_gui(string path_prefix)
459 if (path_prefix.empty())
461 fprintf(stderr, "Path parameter is required for GUI mode\n");
462 exit(1);
464 const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
465 path_prefix += "/gui-";
466 for (unsigned int i = 0; i < plugins.size(); i++)
468 const plugin_metadata_iface *pi = plugins[i];
470 // check for empty item after all the params
471 assert(pi->get_id());
472 assert(pi->get_param_props(pi->get_param_count())->short_name == NULL);
473 assert(pi->get_param_props(pi->get_param_count())->name == NULL);
475 stringstream xml;
476 int graphs = 0;
477 for (int j = 0; j < pi->get_param_count(); j++)
479 const parameter_properties &props = *pi->get_param_props(j);
480 if (props.flags & PF_PROP_GRAPH)
481 graphs++;
483 xml << "<table rows=\"" << pi->get_param_count() << "\" cols=\"" << (graphs ? "4" : "3") << "\">\n";
484 for (int j = 0; j < pi->get_param_count(); j++)
486 if (j)
487 xml << "\n <!-- -->\n\n";
488 const parameter_properties &props = *pi->get_param_props(j);
489 if (!props.short_name)
491 fprintf(stderr, "Plugin %s is missing short name for parameter %d\n", pi->get_name(), j);
492 exit(1);
494 string expand_x = "expand-x=\"1\" ";
495 string fill_x = "fill-x=\"1\" ";
496 string shrink_x = "shrink-x=\"1\" ";
497 string pad_x = "pad-x=\"10\" ";
498 string attach_x = "attach-x=\"1\" attach-w=\"2\" ";
499 string attach_y = "attach-y=\"" + i2s(j) + "\" ";
500 string param = "param=\"" + string(props.short_name) + "\" ";
501 string label = " <align attach-x=\"0\" " + attach_y + " " + " align-x=\"1\"><label " + param + " /></align>\n";
502 string value = " <value " + param + " " + "attach-x=\"2\" " + attach_y + pad_x + "/>\n";
503 string attach_xv = "attach-x=\"1\" attach-w=\"1\" ";
504 string ctl;
505 if ((props.flags & PF_TYPEMASK) == PF_ENUM &&
506 (props.flags & PF_CTLMASK) == PF_CTL_COMBO)
508 ctl = " <combo " + attach_x + attach_y + param + expand_x + pad_x + " />\n";
510 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
511 (props.flags & PF_CTLMASK) == PF_CTL_TOGGLE)
513 ctl = " <align " + attach_x + attach_y + expand_x + fill_x + pad_x + "><toggle " + param + "/></align>\n";
515 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
516 (props.flags & PF_CTLMASK) == PF_CTL_BUTTON)
518 ctl = " <button attach-x=\"0\" attach-w=\"3\" " + expand_x + attach_y + param + pad_x + "/>\n";
519 label.clear();
521 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
522 (props.flags & PF_CTLMASK) == PF_CTL_LED)
524 ctl = " <led " + attach_x + attach_y + param + shrink_x + pad_x + " />\n";
526 else if ((props.flags & PF_CTLMASK) == PF_CTL_METER)
528 if (props.flags & PF_CTLO_LABEL) {
529 attach_x = attach_xv;
530 pad_x.clear();
532 if (props.flags & PF_CTLO_REVERSE)
533 ctl = " <vumeter " + attach_x + attach_y + expand_x + fill_x + param + pad_x + "mode=\"2\"/>\n";
534 else
535 ctl = " <vumeter " + attach_x + attach_y + expand_x + fill_x + param + pad_x + "/>\n";
536 if (props.flags & PF_CTLO_LABEL)
537 ctl += value;
539 else if ((props.flags & PF_CTLMASK) != PF_CTL_FADER)
541 if ((props.flags & PF_UNITMASK) == PF_UNIT_DEG)
542 ctl = " <knob " + attach_xv + attach_y + shrink_x + param + " type=\"3\"/>\n";
543 else
544 ctl = " <knob " + attach_xv + attach_y + shrink_x + param + " />\n";
545 ctl += value;
547 else
549 ctl += " <hscale " + param + " " + attach_x + attach_y + " pad-x=\"10\"/>";
551 if (!label.empty())
552 xml << label;
553 if (!ctl.empty())
554 xml << ctl;
556 if (graphs)
558 xml << " <if cond=\"directlink\">" << endl;
559 xml << " <vbox expand-x=\"1\" fill-x=\"1\" attach-x=\"3\" attach-y=\"0\" attach-h=\"" << pi->get_param_count() << "\">" << endl;
560 for (int j = 0; j < pi->get_param_count(); j++)
562 const parameter_properties &props = *pi->get_param_props(j);
563 if (props.flags & PF_PROP_GRAPH)
565 xml << " <line-graph refresh=\"1\" width=\"160\" param=\"" << props.short_name << "\"/>\n" << endl;
568 xml << " </vbox>" << endl;
569 xml << " </if>" << endl;
571 xml << "</table>\n";
572 FILE *f = open_and_check(path_prefix+string(pi->get_id())+".xml");
573 fprintf(f, "%s\n", xml.str().c_str());
574 fclose(f);
578 int main(int argc, char *argv[])
580 string mode = "rdf";
581 string path_prefix;
582 while(1) {
583 int option_index;
584 int c = getopt_long(argc, argv, "hvm:p:", long_options, &option_index);
585 if (c == -1)
586 break;
587 switch(c) {
588 case 'h':
589 case '?':
590 printf("LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv[0]);
591 return 0;
592 case 'v':
593 printf("%s\n", PACKAGE_STRING);
594 return 0;
595 case 'm':
596 mode = optarg;
597 if (mode != "rdf" && mode != "ttl" && mode != "gui") {
598 fprintf(stderr, "calfmakerdf: Invalid mode %s\n", optarg);
599 return 1;
601 break;
602 case 'p':
603 path_prefix = optarg;
604 if (path_prefix.empty())
606 fprintf(stderr, "calfmakerdf: Path prefix must not be empty\n");
607 exit(1);
609 if (path_prefix[path_prefix.length() - 1] != '/')
610 path_prefix += '/';
611 break;
614 if (false)
617 #if USE_LV2
618 else if (mode == "ttl")
619 make_ttl(path_prefix);
620 #endif
621 else if (mode == "gui")
622 make_gui(path_prefix);
623 else
625 fprintf(stderr, "calfmakerdf: Mode '%s' unsupported in this version\n", mode.c_str());
626 return 1;
628 return 0;