Line Graph: fix cairo radial gradient LED sim in portrait orientation
[calf.git] / src / makerdf.cpp
blob3ba01e4f5724ee21b4d7856b95cd5a4e715c8e79
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_state.h>
27 #include <calf/lv2_urid.h>
28 #endif
29 #include <getopt.h>
30 #include <string.h>
31 #include <set>
33 using namespace std;
34 using namespace calf_utils;
35 using namespace calf_plugins;
37 static struct option long_options[] = {
38 {"help", 0, 0, 'h'},
39 {"version", 0, 0, 'v'},
40 {"mode", 1, 0, 'm'},
41 {"path", 1, 0, 'p'},
42 {0,0,0,0},
45 static FILE *open_and_check(const std::string &filename)
47 FILE *f = fopen(filename.c_str(), "w");
48 if (!f)
50 fprintf(stderr, "Cannot write file '%s': %s\n", filename.c_str(), strerror(errno));
51 exit(1);
53 return f;
56 #if USE_LV2
57 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)
59 stringstream ss;
60 const char *ind = " ";
63 if (ports != "") ports += " , ";
64 ss << "[\n";
65 if (direction) ss << ind << "a lv2:" << direction << "Port ;\n";
66 ss << ind << "a " << type << " ;\n";
67 ss << ind << "lv2:index " << pidx << " ;\n";
68 ss << ind << "lv2:symbol \"" << symbol << "\" ;\n";
69 ss << ind << "lv2:name \"" << name << "\" ;\n";
70 if (optional)
71 ss << ind << "lv2:portProperty lv2:connectionOptional ;\n";
72 if (!strcmp(type, "atom:AtomPort")) {
73 ss << ind << "atom:bufferType atom:Sequence ;\n"
74 << ind << "atom:supports lv2midi:MidiEvent ;" << endl;
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 (((pp.flags & PF_SCALEMASK) != PF_SCALE_GAIN) && 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 atom: <http://lv2plug.in/ns/ext/atom#> .\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 " lv2:extensionData uiext:showInterface ;\n"
241 " lv2:requiredFeature uiext:makeResident ;\n"
242 " uiext:binary <calflv2gui.so> .\n"
243 "\n"
245 #endif
247 map<string, pair<string, string> > id_to_info;
249 for (unsigned int i = 0; i < plugins.size(); i++) {
250 const plugin_metadata_iface *pi = plugins[i];
251 const ladspa_plugin_info &lpi = pi->get_plugin_info();
252 printf("Generating a .ttl file for plugin '%s'\n", lpi.label);
253 fflush(stdout);
254 string unquoted_uri = plugin_uri_prefix + string(lpi.label);
255 string uri = string("<" + unquoted_uri + ">");
256 id_to_info[pi->get_id()] = make_pair(lpi.label, uri);
257 string ttl;
258 ttl = "@prefix : <" + unquoted_uri + "#> .\n" + header + gui_header;
260 #if USE_LV2_GUI
261 for (int j = 0; j < pi->get_param_count(); j++)
263 const parameter_properties &props = *pi->get_param_props(j);
264 if (props.flags & PF_PROP_OUTPUT)
266 string portnot = " uiext:portNotification [\n uiext:plugin " + uri + " ;\n uiext:portIndex " + i2s(j) + "\n] .\n\n";
267 ttl += gtkgui_uri + portnot;
270 #endif
272 if(pi->get_input_count() == 1) {
273 ttl += ":in a pg:MonoGroup , pg:InputGroup ;\n"
274 " lv2:symbol \"in\" ;\n"
275 " rdfs:label \"Input\" .\n\n";
276 } else if(pi->get_input_count() >= 2) {
277 ttl += ":in a pg:StereoGroup , pg:InputGroup ;\n"
278 " lv2:symbol \"in\" ;\n"
279 " rdfs:label \"Input\" .\n\n";
281 if(pi->get_output_count() >= 2) {
282 ttl += ":out a pg:StereoGroup , pg:OutputGroup ;\n"
283 " lv2:symbol \"out\" ;\n"
284 " rdfs:label \"Output\" .\n\n";
287 ttl += uri + " a lv2:Plugin ;\n";
289 if (classes.count(lpi.plugin_type))
290 ttl += " a " + classes[lpi.plugin_type]+" ;\n";
293 ttl += " doap:name \""+string(lpi.name)+"\" ;\n";
294 ttl += " doap:maintainer [ foaf:name \""+string(lpi.maker)+"\" ; ] ;\n";
296 #if USE_LV2_GUI
297 ttl += " uiext:ui <http://calf.sourceforge.net/plugins/gui/gtk2-gui> ;\n";
298 ttl += " lv2:optionalFeature <http://lv2plug.in/ns/ext/instance-access> ;\n";
299 ttl += " lv2:optionalFeature <http://lv2plug.in/ns/ext/data-access> ;\n";
300 #endif
302 ttl += " doap:license <http://usefulinc.com/doap/licenses/lgpl> ;\n";
303 ttl += " dct:replaces <urn:ladspa:" + i2s(lpi.unique_id) + "> ;\n";
304 // XXXKF not really optional for now, to be honest
305 ttl += " lv2:optionalFeature epp:supportsStrictBounds ;\n";
306 if (pi->is_rt_capable())
307 ttl += " lv2:optionalFeature lv2:hardRTCapable ;\n";
308 if (pi->get_midi())
310 if (pi->requires_midi()) {
311 ttl += " lv2:requiredFeature <" LV2_URID_MAP_URI "> ;\n";
313 else {
314 ttl += " lv2:optionalFeature <" LV2_URID_MAP_URI "> ;\n";
318 vector<string> configure_keys;
319 pi->get_configure_vars(configure_keys);
320 if (!configure_keys.empty())
322 ttl += " lv2:extensionData <" LV2_STATE__interface "> ;\n";
325 if(pi->get_input_count() >= 1) {
326 ttl += " pg:mainInput :in ;\n";
328 if(pi->get_output_count() >= 2) {
329 ttl += " pg:mainOutput :out ;\n";
332 string ports = "";
333 int pn = 0;
334 const char *in_symbols[] = { "in_l", "in_r", "sidechain", "sidechain2" };
335 const char *in_names[] = { "In L", "In R", "Sidechain", "Sidechain 2" };
336 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" };
337 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" };
338 for (int i = 0; i < pi->get_input_count(); i++)
339 if(i <= pi->get_input_count() - pi->get_inputs_optional() - 1 && !(i == 1 && pi->get_simulate_stereo_input()))
340 add_port(ports, in_symbols[i], in_names[i], "Input", pn++);
341 else
342 add_port(ports, in_symbols[i], in_names[i], "Input", pn++, "lv2:AudioPort", true);
343 for (int i = 0; i < pi->get_output_count(); i++)
344 if(i <= pi->get_output_count() - pi->get_outputs_optional() - 1)
345 add_port(ports, out_symbols[i], out_names[i], "Output", pn++);
346 else
347 add_port(ports, out_symbols[i], out_names[i], "Output", pn++, "lv2:AudioPort", true);
348 for (int i = 0; i < pi->get_param_count(); i++)
349 if (add_ctl_port(ports, *pi->get_param_props(i), pn, pi, i))
350 pn++;
351 if (pi->get_midi()) {
352 add_port(ports, "midi_in", "MIDI", "Input", pn++, "atom:AtomPort", true);
354 if (!ports.empty())
355 ttl += " lv2:port " + ports + "\n";
356 ttl += ".\n\n";
358 FILE *f = open_and_check(path_prefix+string(lpi.label)+".ttl");
359 fprintf(f, "%s\n", ttl.c_str());
360 fclose(f);
362 // Generate a manifest
363 printf("Writing presets\n");
364 fflush(stdout);
366 // Prefixes for the preset TTL
367 string presets_ttl_head =
368 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
369 "@prefix lv2p: <http://lv2plug.in/ns/ext/presets#> .\n"
370 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
371 "@prefix dct: <http://purl.org/dc/terms/> .\n"
372 "\n"
375 // Prefixes for the manifest TTL
376 string ttl = presets_ttl_head;
378 calf_plugins::get_builtin_presets().load_defaults(true);
379 calf_plugins::preset_vector &factory_presets = calf_plugins::get_builtin_presets().presets;
381 ttl += "\n";
383 // We'll collect TTL for presets here, maps plugin label to TTL generated so far
384 map<string, string> preset_data;
386 for (unsigned int i = 0; i < factory_presets.size(); i++)
388 plugin_preset &pr = factory_presets[i];
389 map<string, pair<string, string> >::iterator ilm = id_to_info.find(pr.plugin);
390 if (ilm == id_to_info.end())
391 continue;
393 string presets_ttl;
394 // if this is the first preset, add a header
395 if (!preset_data.count(ilm->second.first))
396 presets_ttl = presets_ttl_head;
398 string uri = "<http://calf.sourceforge.net/factory_presets#"
399 + pr.plugin + "_" + pr.get_safe_name()
400 + ">";
401 ttl += ilm->second.second + " lv2p:hasPreset\n " + uri + " .\n";
403 presets_ttl += uri +
404 " a lv2p:Preset ;\n"
405 " rdfs:label \"" + pr.name + "\" ;\n"
406 " lv2:appliesTo " + ilm->second.second + " ;\n"
407 " lv2:port \n"
410 unsigned int count = min(pr.param_names.size(), pr.values.size());
411 for (unsigned int j = 0; j < count; j++)
413 presets_ttl += " [ lv2:symbol \"" + pr.param_names[j] + "\" ; lv2p:value " + ff2s(pr.values[j]) + " ] ";
414 if (j < count - 1)
415 presets_ttl += ',';
416 presets_ttl += '\n';
418 presets_ttl += ".\n\n";
420 preset_data[ilm->second.first] += presets_ttl;
422 for (map<string, string>::iterator i = preset_data.begin(); i != preset_data.end(); i++)
424 FILE *f = open_and_check(path_prefix + "presets-" + i->first + ".ttl");
425 fprintf(f, "%s\n", i->second.c_str());
426 fclose(f);
429 printf("Generating a manifest file\n");
430 fflush(stdout);
431 for (unsigned int i = 0; i < plugins.size(); i++)
433 string label = plugins[i]->get_plugin_info().label;
434 ttl += string("<" + plugin_uri_prefix)
435 + string(plugins[i]->get_plugin_info().label)
436 + "> a lv2:Plugin ;\n dct:replaces <urn:ladspa:"
437 + i2s(plugins[i]->get_plugin_info().unique_id) + "> ;\n "
438 + "lv2:binary <calf.so> ; rdfs:seeAlso <" + label + ".ttl> ";
439 if (preset_data.count(label))
440 ttl += ", <presets-" + label + ".ttl>";
441 ttl += ".\n";
444 FILE *f = open_and_check(path_prefix+"manifest.ttl");
445 fprintf(f, "%s\n", ttl.c_str());
446 fclose(f);
450 #else
451 void make_ttl(string tmp)
453 fprintf(stderr, "LV2 not supported.\n");
456 #endif
458 void make_gui(string path_prefix)
460 if (path_prefix.empty())
462 fprintf(stderr, "Path parameter is required for GUI mode\n");
463 exit(1);
465 const plugin_registry::plugin_vector &plugins = plugin_registry::instance().get_all();
466 path_prefix += "/gui-";
467 for (unsigned int i = 0; i < plugins.size(); i++)
469 const plugin_metadata_iface *pi = plugins[i];
471 // check for empty item after all the params
472 assert(pi->get_id());
473 assert(pi->get_param_props(pi->get_param_count())->short_name == NULL);
474 assert(pi->get_param_props(pi->get_param_count())->name == NULL);
476 stringstream xml;
477 int graphs = 0;
478 for (int j = 0; j < pi->get_param_count(); j++)
480 const parameter_properties &props = *pi->get_param_props(j);
481 if (props.flags & PF_PROP_GRAPH)
482 graphs++;
484 xml << "<table rows=\"" << pi->get_param_count() << "\" cols=\"" << (graphs ? "4" : "3") << "\">\n";
485 for (int j = 0; j < pi->get_param_count(); j++)
487 if (j)
488 xml << "\n <!-- -->\n\n";
489 const parameter_properties &props = *pi->get_param_props(j);
490 if (!props.short_name)
492 fprintf(stderr, "Plugin %s is missing short name for parameter %d\n", pi->get_name(), j);
493 exit(1);
495 string expand_x = "expand-x=\"1\" ";
496 string fill_x = "fill-x=\"1\" ";
497 string shrink_x = "shrink-x=\"1\" ";
498 string pad_x = "pad-x=\"10\" ";
499 string attach_x = "attach-x=\"1\" attach-w=\"2\" ";
500 string attach_y = "attach-y=\"" + i2s(j) + "\" ";
501 string param = "param=\"" + string(props.short_name) + "\" ";
502 string label = " <align attach-x=\"0\" " + attach_y + " " + " align-x=\"1\"><label " + param + " /></align>\n";
503 string value = " <value " + param + " " + "attach-x=\"2\" " + attach_y + pad_x + "/>\n";
504 string attach_xv = "attach-x=\"1\" attach-w=\"1\" ";
505 string ctl;
506 if ((props.flags & PF_TYPEMASK) == PF_ENUM &&
507 (props.flags & PF_CTLMASK) == PF_CTL_COMBO)
509 ctl = " <combo " + attach_x + attach_y + param + expand_x + pad_x + " />\n";
511 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
512 (props.flags & PF_CTLMASK) == PF_CTL_TOGGLE)
514 ctl = " <align " + attach_x + attach_y + expand_x + fill_x + pad_x + "><toggle " + param + "/></align>\n";
516 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
517 (props.flags & PF_CTLMASK) == PF_CTL_BUTTON)
519 ctl = " <button attach-x=\"0\" attach-w=\"3\" " + expand_x + attach_y + param + pad_x + "/>\n";
520 label.clear();
522 else if ((props.flags & PF_TYPEMASK) == PF_BOOL &&
523 (props.flags & PF_CTLMASK) == PF_CTL_LED)
525 ctl = " <led " + attach_x + attach_y + param + shrink_x + pad_x + " />\n";
527 else if ((props.flags & PF_CTLMASK) == PF_CTL_METER)
529 if (props.flags & PF_CTLO_LABEL) {
530 attach_x = attach_xv;
531 pad_x.clear();
533 if (props.flags & PF_CTLO_REVERSE)
534 ctl = " <vumeter " + attach_x + attach_y + expand_x + fill_x + param + pad_x + "mode=\"2\"/>\n";
535 else
536 ctl = " <vumeter " + attach_x + attach_y + expand_x + fill_x + param + pad_x + "/>\n";
537 if (props.flags & PF_CTLO_LABEL)
538 ctl += value;
540 else if ((props.flags & PF_CTLMASK) != PF_CTL_FADER)
542 if ((props.flags & PF_UNITMASK) == PF_UNIT_DEG)
543 ctl = " <knob " + attach_xv + attach_y + shrink_x + param + " type=\"3\"/>\n";
544 else
545 ctl = " <knob " + attach_xv + attach_y + shrink_x + param + " />\n";
546 ctl += value;
548 else
550 ctl += " <hscale " + param + " " + attach_x + attach_y + " pad-x=\"10\"/>";
552 if (!label.empty())
553 xml << label;
554 if (!ctl.empty())
555 xml << ctl;
557 if (graphs)
559 xml << " <if cond=\"directlink\">" << endl;
560 xml << " <vbox expand-x=\"1\" fill-x=\"1\" attach-x=\"3\" attach-y=\"0\" attach-h=\"" << pi->get_param_count() << "\">" << endl;
561 for (int j = 0; j < pi->get_param_count(); j++)
563 const parameter_properties &props = *pi->get_param_props(j);
564 if (props.flags & PF_PROP_GRAPH)
566 xml << " <line-graph refresh=\"1\" width=\"160\" param=\"" << props.short_name << "\"/>\n" << endl;
569 xml << " </vbox>" << endl;
570 xml << " </if>" << endl;
572 xml << "</table>\n";
573 FILE *f = open_and_check(path_prefix+string(pi->get_id())+".xml");
574 fprintf(f, "%s\n", xml.str().c_str());
575 fclose(f);
579 int main(int argc, char *argv[])
581 string mode = "rdf";
582 string path_prefix;
583 while(1) {
584 int option_index;
585 int c = getopt_long(argc, argv, "hvm:p:", long_options, &option_index);
586 if (c == -1)
587 break;
588 switch(c) {
589 case 'h':
590 case '?':
591 printf("LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv[0]);
592 return 0;
593 case 'v':
594 printf("%s\n", PACKAGE_STRING);
595 return 0;
596 case 'm':
597 mode = optarg;
598 if (mode != "rdf" && mode != "ttl" && mode != "gui") {
599 fprintf(stderr, "calfmakerdf: Invalid mode %s\n", optarg);
600 return 1;
602 break;
603 case 'p':
604 path_prefix = optarg;
605 if (path_prefix.empty())
607 fprintf(stderr, "calfmakerdf: Path prefix must not be empty\n");
608 exit(1);
610 if (path_prefix[path_prefix.length() - 1] != '/')
611 path_prefix += '/';
612 break;
615 if (false)
618 #if USE_LV2
619 else if (mode == "ttl")
620 make_ttl(path_prefix);
621 #endif
622 else if (mode == "gui")
623 make_gui(path_prefix);
624 else
626 fprintf(stderr, "calfmakerdf: Mode '%s' unsupported in this version\n", mode.c_str());
627 return 1;
629 return 0;