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_state.h>
27 #include <calf/lv2_urid.h>
34 using namespace calf_utils
;
35 using namespace calf_plugins
;
37 static struct option long_options
[] = {
39 {"version", 0, 0, 'v'},
43 {"data-dir", 1, 0, 'd'},
48 static FILE *open_and_check(const std::string
&filename
)
50 FILE *f
= fopen(filename
.c_str(), "w");
53 fprintf(stderr
, "Cannot write file '%s': %s\n", filename
.c_str(), strerror(errno
));
60 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)
63 const char *ind
= " ";
66 if (ports
!= "") ports
+= " , ";
68 if (direction
) ss
<< ind
<< "a lv2:" << direction
<< "Port ;\n";
69 ss
<< ind
<< "a " << type
<< " ;\n";
70 ss
<< ind
<< "lv2:index " << pidx
<< " ;\n";
71 ss
<< ind
<< "lv2:symbol \"" << symbol
<< "\" ;\n";
72 ss
<< ind
<< "lv2:name \"" << name
<< "\" ;\n";
74 ss
<< ind
<< "lv2:portProperty lv2:connectionOptional ;\n";
75 if (!strcmp(type
, "atom:AtomPort")) {
76 ss
<< ind
<< "atom:bufferType atom:Sequence ;\n"
77 << ind
<< "atom:supports lv2midi:MidiEvent ;" << endl
;
79 if (!strcmp(std::string(symbol
, 0, 4).c_str(), "in_l"))
80 ss
<< ind
<< "lv2:designation pg:left ;\n"
81 << ind
<< "pg:group :in ;" << endl
;
83 if (!strcmp(std::string(symbol
, 0, 4).c_str(), "in_r"))
84 ss
<< ind
<< "lv2:designation pg:right ;\n"
85 << ind
<< "pg:group :in ;" << endl
;
87 if (!strcmp(std::string(symbol
, 0, 5).c_str(), "out_l"))
88 ss
<< ind
<< "lv2:designation pg:left ;\n"
89 << ind
<< "pg:group :out ;" << endl
;
91 if (!strcmp(std::string(symbol
, 0, 5).c_str(), "out_r"))
92 ss
<< ind
<< "lv2:designation pg:right ;\n"
93 << ind
<< "pg:group :out ;" << endl
;
98 static const char *units
[] = {
109 NULL
// rotations per minute
112 //////////////// To all haters: calm down, I'll rewrite it to use the new interface one day
114 static bool add_ctl_port(string
&ports
, const parameter_properties
&pp
, int pidx
, const plugin_metadata_iface
*pmi
, int param
)
117 const char *ind
= " ";
119 parameter_flags type
= (parameter_flags
)(pp
.flags
& PF_TYPEMASK
);
120 uint8_t unit
= (pp
.flags
& PF_UNITMASK
) >> 24;
122 if (ports
!= "") ports
+= " , ";
124 if (pp
.flags
& PF_PROP_OUTPUT
)
125 ss
<< ind
<< "a lv2:OutputPort ;\n";
127 ss
<< ind
<< "a lv2:InputPort ;\n";
128 ss
<< ind
<< "a lv2:ControlPort ;\n";
129 ss
<< ind
<< "lv2:index " << pidx
<< " ;\n";
130 ss
<< ind
<< "lv2:symbol \"" << pp
.short_name
<< "\" ;\n";
131 ss
<< ind
<< "lv2:name \"" << pp
.name
<< "\" ;\n";
132 if ((pp
.flags
& PF_CTLMASK
) == PF_CTL_BUTTON
)
133 ss
<< ind
<< "lv2:portProperty epp:trigger ;\n";
134 if (!(pp
.flags
& PF_PROP_NOBOUNDS
))
135 ss
<< ind
<< "lv2:portProperty epp:hasStrictBounds ;\n";
136 if (pp
.flags
& PF_PROP_EXPENSIVE
)
137 ss
<< ind
<< "lv2:portProperty epp:expensive ;\n";
138 if (pp
.flags
& PF_PROP_OPTIONAL
)
139 ss
<< ind
<< "lv2:portProperty lv2:connectionOptional ;\n";
140 if (pmi
->is_noisy(param
))
141 ss
<< ind
<< "lv2:portProperty epp:causesArtifacts ;\n";
142 if (!pmi
->is_cv(param
))
143 ss
<< ind
<< "lv2:portProperty epp:notAutomatic ;\n";
144 if (pp
.flags
& PF_PROP_OUTPUT_GAIN
)
145 ss
<< ind
<< "lv2:designation param:gain ;\n";
147 ss
<< ind
<< "lv2:portProperty lv2:toggled ;\n";
148 else if (type
== PF_ENUM
)
150 ss
<< ind
<< "lv2:portProperty lv2:integer ;\n";
151 ss
<< ind
<< "lv2:portProperty lv2:enumeration ;\n";
152 for (int i
= (int)pp
.min
; i
<= (int)pp
.max
; i
++)
153 ss
<< ind
<< "lv2:scalePoint [ rdfs:label \"" << pp
.choices
[i
- (int)pp
.min
] << "\"; rdf:value " << i
<<" ] ;\n";
155 else if (type
== PF_INT
|| type
== PF_ENUM_MULTI
)
156 ss
<< ind
<< "lv2:portProperty lv2:integer ;\n";
157 else if ((pp
.flags
& PF_SCALEMASK
) == PF_SCALE_LOG
)
158 ss
<< ind
<< "lv2:portProperty epp:logarithmic ;\n";
160 if (!(pp
.flags
& PF_PROP_OUTPUT
))
161 ss
<< ind
<< "lv2:default " << pp
.def_value
<< " ;\n";
162 ss
<< ind
<< "lv2:minimum " << pp
.min
<< " ;\n";
163 ss
<< ind
<< "lv2:maximum " << pp
.max
<< " ;\n";
164 // XXX This value does not seem to match the definition of the property
166 // ss << ind << "epp:rangeSteps " << pp.step << " ;\n";
167 if (((pp
.flags
& PF_SCALEMASK
) != PF_SCALE_GAIN
) && unit
> 0 && unit
< (sizeof(units
) / sizeof(char *)) && units
[unit
- 1] != NULL
)
168 ss
<< ind
<< "ue:unit " << units
[unit
- 1] << " ;\n";
170 // for now I assume that the only tempo passed is the tempo the plugin should operate with
171 // this may change as more complex plugins are added
173 if ((pp
.flags
& PF_SYNC_BPM
))
174 ss
<< ind
<< "lv2:designation <http://lv2plug.in/ns/ext/time#beatsPerMinute> ;\n";
181 void make_ttl(string path_prefix
, const string
*data_dir
)
183 if (path_prefix
.empty())
185 fprintf(stderr
, "Path parameter is required for TTL mode\n");
191 "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
192 "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n"
193 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
194 "@prefix dct: <http://purl.org/dc/terms/> .\n"
195 "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
196 "@prefix uiext: <http://lv2plug.in/ns/extensions/ui#> .\n"
197 "@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n"
198 "@prefix lv2midi: <http://lv2plug.in/ns/ext/midi#> .\n"
199 "@prefix lv2ctx: <http://lv2plug.in/ns/dev/contexts#> .\n"
200 "@prefix strport: <http://lv2plug.in/ns/dev/string-port#> .\n"
201 "@prefix pg: <http://lv2plug.in/ns/ext/port-groups#> .\n"
202 "@prefix ue: <http://lv2plug.in/ns/extensions/units#> .\n"
203 "@prefix epp: <http://lv2plug.in/ns/ext/port-props#> .\n"
204 "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
205 "@prefix param: <http://lv2plug.in/ns/ext/parameters#> .\n"
210 printf("Retrieving plugin list\n");
212 const plugin_registry::plugin_vector
&plugins
= plugin_registry::instance().get_all();
214 map
<string
, string
> classes
;
216 printf("Creating a list of plugin classes\n");
218 const char *ptypes
[] = {
219 "Flanger", "Reverb", "Generator", "Instrument", "Oscillator",
220 "Utility", "Converter", "Analyser", "Mixer", "Simulator",
221 "Delay", "Modulator", "Phaser", "Chorus", "Filter",
222 "Lowpass", "Highpass", "Bandpass", "Comb", "Allpass",
223 "Amplifier", "Distortion", "Waveshaper", "Dynamics", "Compressor",
224 "Expander", "Limiter", "Gate", "EQ", "ParaEQ", "MultiEQ", "Spatial",
225 "Spectral", "Pitch", "Envelope", "Function", "Constant",
229 for(const char **p
= ptypes
; *p
; p
++) {
230 string name
= string(*p
) + "Plugin";
231 classes
[name
] = "lv2:" + name
;
233 classes
["SynthesizerPlugin"] = "lv2:InstrumentPlugin";
235 string plugin_uri_prefix
= "http://calf.sourceforge.net/plugins/";
240 string gtkgui_uri
= "<http://calf.sourceforge.net/plugins/gui/gtk2-gui>";
241 gui_header
= gtkgui_uri
+ "\n"
243 " lv2:extensionData uiext:showInterface ;\n"
244 " lv2:requiredFeature uiext:makeResident ;\n"
245 " uiext:binary <calflv2gui.so> .\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_URID_MAP_URI
"> ;\n";
317 ttl
+= " lv2:optionalFeature <" LV2_URID_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
, "midi_in", "MIDI", "Input", pn
++, "atom:AtomPort", 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, data_dir
);
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
[])
587 string pkglibdir_path
;
591 int c
= getopt_long(argc
, argv
, "hvm:p:"
595 , long_options
, &option_index
);
601 printf("LV2 TTL / XML GUI generator for Calf plugin pack\nSyntax: %s [--help] [--version] [--mode rdf|ttl|gui] [--path <path>]\n", argv
[0]);
604 printf("%s\n", PACKAGE_STRING
);
608 if (mode
!= "rdf" && mode
!= "ttl" && mode
!= "gui") {
609 fprintf(stderr
, "calfmakerdf: Invalid mode %s\n", optarg
);
615 pkglibdir_path
= optarg
;
616 if (pkglibdir_path
.empty())
618 fprintf(stderr
, "calfmakerdf: Data directory must not be empty\n");
621 if (pkglibdir_path
[path_prefix
.length() - 1] != '/')
622 pkglibdir_path
+= '/';
626 path_prefix
= optarg
;
627 if (path_prefix
.empty())
629 fprintf(stderr
, "calfmakerdf: Path prefix must not be empty\n");
632 if (path_prefix
[path_prefix
.length() - 1] != '/')
639 make_ttl(path_prefix
, !pkglibdir_path
.empty() ? &pkglibdir_path
: NULL
);
643 make_gui(path_prefix
);
646 fprintf(stderr
, "calfmakerdf: Mode '%s' unsupported in this version\n", mode
.c_str());