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>
26 #include <calf/lv2_event.h>
27 #include <calf/lv2_state.h>
28 #include <calf/lv2_uri_map.h>
35 using namespace calf_utils
;
36 using namespace calf_plugins
;
38 static struct option long_options
[] = {
40 {"version", 0, 0, 'v'},
46 static FILE *open_and_check(const std::string
&filename
)
48 FILE *f
= fopen(filename
.c_str(), "w");
51 fprintf(stderr
, "Cannot write file '%s': %s\n", filename
.c_str(), strerror(errno
));
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)
61 const char *ind
= " ";
64 if (ports
!= "") ports
+= " , ";
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";
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
;
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
;
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
;
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
;
95 static const char *units
[] = {
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
)
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
+= " , ";
121 if (pp
.flags
& PF_PROP_OUTPUT
)
122 ss
<< ind
<< "a lv2:OutputPort ;\n";
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";
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";
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
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 // Markus: This entry binds BPM to the hosts BPM setting, so delays
171 // are fixed within multitrack environments, disabling it to fix
172 // some reported bugs
174 // if (unit == (PF_UNIT_BPM >> 24))
175 // ss << ind << "lv2:designation <http://lv2plug.in/ns/ext/time#beatsPerMinute> ;\n";
182 void make_ttl(string path_prefix
)
184 if (path_prefix
.empty())
186 fprintf(stderr
, "Path parameter is required for TTL mode\n");
192 "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
193 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
194 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
195 "@prefix dct: <http://purl.org/dc/terms/> .\n"
196 "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
197 "@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> .\n"
198 "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .\n"
199 "@prefix lv2midi: <http://lv2plug.in/ns/ext/midi#> .\n"
200 "@prefix lv2ctx: <http://lv2plug.in/ns/dev/contexts#> .\n"
201 "@prefix strport: <http://lv2plug.in/ns/dev/string-port#> .\n"
202 "@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .\n"
203 "@prefix ue: <http://lv2plug.in/ns/extensions/units#> .\n"
204 "@prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n"
205 "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
206 "@prefix param: <http://lv2plug.in/ns/ext/parameters#> .\n"
211 printf("Retrieving plugin list\n");
213 const plugin_registry::plugin_vector
&plugins
= plugin_registry::instance().get_all();
215 map
<string
, string
> classes
;
217 printf("Creating a list of plugin classes\n");
219 const char *ptypes
[] = {
220 "Flanger", "Reverb", "Generator", "Instrument", "Oscillator",
221 "Utility", "Converter", "Analyser", "Mixer", "Simulator",
222 "Delay", "Modulator", "Phaser", "Chorus", "Filter",
223 "Lowpass", "Highpass", "Bandpass", "Comb", "Allpass",
224 "Amplifier", "Distortion", "Waveshaper", "Dynamics", "Compressor",
225 "Expander", "Limiter", "Gate", "EQ", "ParaEQ", "MultiEQ", "Spatial",
226 "Spectral", "Pitch", "Envelope", "Function", "Constant",
230 for(const char **p
= ptypes
; *p
; p
++) {
231 string name
= string(*p
) + "Plugin";
232 classes
[name
] = "lv2:" + name
;
234 classes
["SynthesizerPlugin"] = "lv2:InstrumentPlugin";
236 string plugin_uri_prefix
= "http://calf.sourceforge.net/plugins/";
241 string gtkgui_uri
= "<http://calf.sourceforge.net/plugins/gui/gtk2-gui>";
242 gui_header
= gtkgui_uri
+ "\n"
244 " uiext:binary <calflv2gui.so> ;\n"
245 " uiext:requiredFeature uiext:makeResident .\n"
250 map
<string
, pair
<string
, string
> > id_to_info
;
252 for (unsigned int i
= 0; i
< plugins
.size(); i
++) {
253 const plugin_metadata_iface
*pi
= plugins
[i
];
254 const ladspa_plugin_info
&lpi
= pi
->get_plugin_info();
255 printf("Generating a .ttl file for plugin '%s'\n", lpi
.label
);
257 string unquoted_uri
= plugin_uri_prefix
+ string(lpi
.label
);
258 string uri
= string("<" + unquoted_uri
+ ">");
259 id_to_info
[pi
->get_id()] = make_pair(lpi
.label
, uri
);
261 ttl
= "@prefix : <" + unquoted_uri
+ "#> .\n" + header
+ gui_header
;
264 for (int j
= 0; j
< pi
->get_param_count(); j
++)
266 const parameter_properties
&props
= *pi
->get_param_props(j
);
267 if (props
.flags
& PF_PROP_OUTPUT
)
269 string portnot
= " uiext:portNotification [\n uiext:plugin " + uri
+ " ;\n uiext:portIndex " + i2s(j
) + "\n] .\n\n";
270 ttl
+= gtkgui_uri
+ portnot
;
275 if(pi
->get_input_count() == 1) {
276 ttl
+= ":in a pg:MonoGroup , pg:InputGroup ;\n"
277 " lv2:symbol \"in\" ;\n"
278 " rdfs:label \"Input\" .\n\n";
279 } else if(pi
->get_input_count() >= 2) {
280 ttl
+= ":in a pg:StereoGroup , pg:InputGroup ;\n"
281 " lv2:symbol \"in\" ;\n"
282 " rdfs:label \"Input\" .\n\n";
284 if(pi
->get_output_count() >= 2) {
285 ttl
+= ":out a pg:StereoGroup , pg:OutputGroup ;\n"
286 " lv2:symbol \"out\" ;\n"
287 " rdfs:label \"Output\" .\n\n";
290 ttl
+= uri
+ " a lv2:Plugin ;\n";
292 if (classes
.count(lpi
.plugin_type
))
293 ttl
+= " a " + classes
[lpi
.plugin_type
]+" ;\n";
296 ttl
+= " doap:name \""+string(lpi
.name
)+"\" ;\n";
297 ttl
+= " doap:maintainer [ foaf:name \""+string(lpi
.maker
)+"\" ; ] ;\n";
300 ttl
+= " uiext:ui <http://calf.sourceforge.net/plugins/gui/gtk2-gui> ;\n";
301 ttl
+= " lv2:optionalFeature <http://lv2plug.in/ns/ext/instance-access> ;\n";
302 ttl
+= " lv2:optionalFeature <http://lv2plug.in/ns/ext/data-access> ;\n";
305 ttl
+= " doap:license <http://usefulinc.com/doap/licenses/lgpl> ;\n";
306 ttl
+= " dct:replaces <urn:ladspa:" + i2s(lpi
.unique_id
) + "> ;\n";
307 // XXXKF not really optional for now, to be honest
308 ttl
+= " lv2:optionalFeature epp:supportsStrictBounds ;\n";
309 if (pi
->is_rt_capable())
310 ttl
+= " lv2:optionalFeature lv2:hardRTCapable ;\n";
313 if (pi
->requires_midi()) {
314 ttl
+= " lv2:requiredFeature <" LV2_URI_MAP_URI
"> ;\n";
317 ttl
+= " lv2:optionalFeature <" LV2_URI_MAP_URI
"> ;\n";
321 vector
<string
> configure_keys
;
322 pi
->get_configure_vars(configure_keys
);
323 if (!configure_keys
.empty())
325 ttl
+= " lv2:extensionData <" LV2_STATE__interface
"> ;\n";
328 if(pi
->get_input_count() >= 1) {
329 ttl
+= " pg:mainInput :in ;\n";
331 if(pi
->get_output_count() >= 2) {
332 ttl
+= " pg:mainOutput :out ;\n";
337 const char *in_symbols
[] = { "in_l", "in_r", "sidechain", "sidechain2" };
338 const char *in_names
[] = { "In L", "In R", "Sidechain", "Sidechain 2" };
339 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" };
340 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" };
341 for (int i
= 0; i
< pi
->get_input_count(); i
++)
342 if(i
<= pi
->get_input_count() - pi
->get_inputs_optional() - 1 && !(i
== 1 && pi
->get_simulate_stereo_input()))
343 add_port(ports
, in_symbols
[i
], in_names
[i
], "Input", pn
++);
345 add_port(ports
, in_symbols
[i
], in_names
[i
], "Input", pn
++, "lv2:AudioPort", true);
346 for (int i
= 0; i
< pi
->get_output_count(); i
++)
347 if(i
<= pi
->get_output_count() - pi
->get_outputs_optional() - 1)
348 add_port(ports
, out_symbols
[i
], out_names
[i
], "Output", pn
++);
350 add_port(ports
, out_symbols
[i
], out_names
[i
], "Output", pn
++, "lv2:AudioPort", true);
351 for (int i
= 0; i
< pi
->get_param_count(); i
++)
352 if (add_ctl_port(ports
, *pi
->get_param_props(i
), pn
, pi
, i
))
354 if (pi
->get_midi()) {
355 add_port(ports
, "event_in", "Event", "Input", pn
++, "lv2ev:EventPort", true);
358 ttl
+= " lv2:port " + ports
+ "\n";
361 FILE *f
= open_and_check(path_prefix
+string(lpi
.label
)+".ttl");
362 fprintf(f
, "%s\n", ttl
.c_str());
365 // Generate a manifest
366 printf("Writing presets\n");
369 // Prefixes for the preset TTL
370 string presets_ttl_head
=
371 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
372 "@prefix lv2p: <http://lv2plug.in/ns/ext/presets#> .\n"
373 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
374 "@prefix dct: <http://purl.org/dc/terms/> .\n"
378 // Prefixes for the manifest TTL
379 string ttl
= presets_ttl_head
;
381 calf_plugins::get_builtin_presets().load_defaults(true);
382 calf_plugins::preset_vector
&factory_presets
= calf_plugins::get_builtin_presets().presets
;
386 // We'll collect TTL for presets here, maps plugin label to TTL generated so far
387 map
<string
, string
> preset_data
;
389 for (unsigned int i
= 0; i
< factory_presets
.size(); i
++)
391 plugin_preset
&pr
= factory_presets
[i
];
392 map
<string
, pair
<string
, string
> >::iterator ilm
= id_to_info
.find(pr
.plugin
);
393 if (ilm
== id_to_info
.end())
397 // if this is the first preset, add a header
398 if (!preset_data
.count(ilm
->second
.first
))
399 presets_ttl
= presets_ttl_head
;
401 string uri
= "<http://calf.sourceforge.net/factory_presets#"
402 + pr
.plugin
+ "_" + pr
.get_safe_name()
404 ttl
+= ilm
->second
.second
+ " lv2p:hasPreset\n " + uri
+ " .\n";
408 " rdfs:label \"" + pr
.name
+ "\" ;\n"
409 " lv2:appliesTo " + ilm
->second
.second
+ " ;\n"
413 unsigned int count
= min(pr
.param_names
.size(), pr
.values
.size());
414 for (unsigned int j
= 0; j
< count
; j
++)
416 presets_ttl
+= " [ lv2:symbol \"" + pr
.param_names
[j
] + "\" ; lv2p:value " + ff2s(pr
.values
[j
]) + " ] ";
421 presets_ttl
+= ".\n\n";
423 preset_data
[ilm
->second
.first
] += presets_ttl
;
425 for (map
<string
, string
>::iterator i
= preset_data
.begin(); i
!= preset_data
.end(); i
++)
427 FILE *f
= open_and_check(path_prefix
+ "presets-" + i
->first
+ ".ttl");
428 fprintf(f
, "%s\n", i
->second
.c_str());
432 printf("Generating a manifest file\n");
434 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
436 string label
= plugins
[i
]->get_plugin_info().label
;
437 ttl
+= string("<" + plugin_uri_prefix
)
438 + string(plugins
[i
]->get_plugin_info().label
)
439 + "> a lv2:Plugin ;\n dct:replaces <urn:ladspa:"
440 + i2s(plugins
[i
]->get_plugin_info().unique_id
) + "> ;\n "
441 + "lv2:binary <calf.so> ; rdfs:seeAlso <" + label
+ ".ttl> ";
442 if (preset_data
.count(label
))
443 ttl
+= ", <presets-" + label
+ ".ttl>";
447 FILE *f
= open_and_check(path_prefix
+"manifest.ttl");
448 fprintf(f
, "%s\n", ttl
.c_str());
454 void make_ttl(string tmp
)
456 fprintf(stderr
, "LV2 not supported.\n");
461 void make_gui(string path_prefix
)
463 if (path_prefix
.empty())
465 fprintf(stderr
, "Path parameter is required for GUI mode\n");
468 const plugin_registry::plugin_vector
&plugins
= plugin_registry::instance().get_all();
469 path_prefix
+= "/gui-";
470 for (unsigned int i
= 0; i
< plugins
.size(); i
++)
472 const plugin_metadata_iface
*pi
= plugins
[i
];
474 // check for empty item after all the params
475 assert(pi
->get_id());
476 assert(pi
->get_param_props(pi
->get_param_count())->short_name
== NULL
);
477 assert(pi
->get_param_props(pi
->get_param_count())->name
== NULL
);
481 for (int j
= 0; j
< pi
->get_param_count(); j
++)
483 const parameter_properties
&props
= *pi
->get_param_props(j
);
484 if (props
.flags
& PF_PROP_GRAPH
)
487 xml
<< "<table rows=\"" << pi
->get_param_count() << "\" cols=\"" << (graphs
? "4" : "3") << "\">\n";
488 for (int j
= 0; j
< pi
->get_param_count(); j
++)
491 xml
<< "\n <!-- -->\n\n";
492 const parameter_properties
&props
= *pi
->get_param_props(j
);
493 if (!props
.short_name
)
495 fprintf(stderr
, "Plugin %s is missing short name for parameter %d\n", pi
->get_name(), j
);
498 string expand_x
= "expand-x=\"1\" ";
499 string fill_x
= "fill-x=\"1\" ";
500 string shrink_x
= "shrink-x=\"1\" ";
501 string pad_x
= "pad-x=\"10\" ";
502 string attach_x
= "attach-x=\"1\" attach-w=\"2\" ";
503 string attach_y
= "attach-y=\"" + i2s(j
) + "\" ";
504 string param
= "param=\"" + string(props
.short_name
) + "\" ";
505 string label
= " <align attach-x=\"0\" " + attach_y
+ " " + " align-x=\"1\"><label " + param
+ " /></align>\n";
506 string value
= " <value " + param
+ " " + "attach-x=\"2\" " + attach_y
+ pad_x
+ "/>\n";
507 string attach_xv
= "attach-x=\"1\" attach-w=\"1\" ";
509 if ((props
.flags
& PF_TYPEMASK
) == PF_ENUM
&&
510 (props
.flags
& PF_CTLMASK
) == PF_CTL_COMBO
)
512 ctl
= " <combo " + attach_x
+ attach_y
+ param
+ expand_x
+ pad_x
+ " />\n";
514 else if ((props
.flags
& PF_TYPEMASK
) == PF_BOOL
&&
515 (props
.flags
& PF_CTLMASK
) == PF_CTL_TOGGLE
)
517 ctl
= " <align " + attach_x
+ attach_y
+ expand_x
+ fill_x
+ pad_x
+ "><toggle " + param
+ "/></align>\n";
519 else if ((props
.flags
& PF_TYPEMASK
) == PF_BOOL
&&
520 (props
.flags
& PF_CTLMASK
) == PF_CTL_BUTTON
)
522 ctl
= " <button attach-x=\"0\" attach-w=\"3\" " + expand_x
+ attach_y
+ param
+ pad_x
+ "/>\n";
525 else if ((props
.flags
& PF_TYPEMASK
) == PF_BOOL
&&
526 (props
.flags
& PF_CTLMASK
) == PF_CTL_LED
)
528 ctl
= " <led " + attach_x
+ attach_y
+ param
+ shrink_x
+ pad_x
+ " />\n";
530 else if ((props
.flags
& PF_CTLMASK
) == PF_CTL_METER
)
532 if (props
.flags
& PF_CTLO_LABEL
) {
533 attach_x
= attach_xv
;
536 if (props
.flags
& PF_CTLO_REVERSE
)
537 ctl
= " <vumeter " + attach_x
+ attach_y
+ expand_x
+ fill_x
+ param
+ pad_x
+ "mode=\"2\"/>\n";
539 ctl
= " <vumeter " + attach_x
+ attach_y
+ expand_x
+ fill_x
+ param
+ pad_x
+ "/>\n";
540 if (props
.flags
& PF_CTLO_LABEL
)
543 else if ((props
.flags
& PF_CTLMASK
) != PF_CTL_FADER
)
545 if ((props
.flags
& PF_UNITMASK
) == PF_UNIT_DEG
)
546 ctl
= " <knob " + attach_xv
+ attach_y
+ shrink_x
+ param
+ " type=\"3\"/>\n";
548 ctl
= " <knob " + attach_xv
+ attach_y
+ shrink_x
+ param
+ " />\n";
553 ctl
+= " <hscale " + param
+ " " + attach_x
+ attach_y
+ " pad-x=\"10\"/>";
562 xml
<< " <if cond=\"directlink\">" << endl
;
563 xml
<< " <vbox expand-x=\"1\" fill-x=\"1\" attach-x=\"3\" attach-y=\"0\" attach-h=\"" << pi
->get_param_count() << "\">" << endl
;
564 for (int j
= 0; j
< pi
->get_param_count(); j
++)
566 const parameter_properties
&props
= *pi
->get_param_props(j
);
567 if (props
.flags
& PF_PROP_GRAPH
)
569 xml
<< " <line-graph refresh=\"1\" width=\"160\" param=\"" << props
.short_name
<< "\"/>\n" << endl
;
572 xml
<< " </vbox>" << endl
;
573 xml
<< " </if>" << endl
;
576 FILE *f
= open_and_check(path_prefix
+string(pi
->get_id())+".xml");
577 fprintf(f
, "%s\n", xml
.str().c_str());
582 int main(int argc
, char *argv
[])
588 int c
= getopt_long(argc
, argv
, "hvm:p:", long_options
, &option_index
);
594 printf("LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv
[0]);
597 printf("%s\n", PACKAGE_STRING
);
601 if (mode
!= "rdf" && mode
!= "ttl" && mode
!= "gui") {
602 fprintf(stderr
, "calfmakerdf: Invalid mode %s\n", optarg
);
607 path_prefix
= optarg
;
608 if (path_prefix
.empty())
610 fprintf(stderr
, "calfmakerdf: Path prefix must not be empty\n");
613 if (path_prefix
[path_prefix
.length() - 1] != '/')
622 else if (mode
== "ttl")
623 make_ttl(path_prefix
);
625 else if (mode
== "gui")
626 make_gui(path_prefix
);
629 fprintf(stderr
, "calfmakerdf: Mode '%s' unsupported in this version\n", mode
.c_str());