Fix UI RDF info
[juce-lv2.git] / juce / source / src / audio / plugin_client / LV2 / lv2_rdf_gen.cpp
blob387e350726f22067c0bceb7c5c5f27290fbf1f0c
1 /*
2 * LV2 ttl generator for JUCE Plugins
3 */
5 #include <fstream>
6 #include <iostream>
7 #include <stdint.h>
9 #include "juce.h"
10 #include "JucePluginCharacteristics.h"
12 // These are dummy values!
13 enum FakePlugCategory
15 kPlugCategUnknown,
16 kPlugCategEffect,
17 kPlugCategSynth,
18 kPlugCategAnalysis,
19 kPlugCategMastering,
20 kPlugCategSpacializer,
21 kPlugCategRoomFx,
22 kPlugSurroundFx,
23 kPlugCategRestoration,
24 kPlugCategOfflineProcess,
25 kPlugCategGenerator
28 extern AudioProcessor* JUCE_CALLTYPE createPluginFilter();
30 String name_to_symbol(String Name)
32 String Symbol = Name.trimStart().trimEnd().replace(" ", "_").toLowerCase();
34 for (int i=0; i < Symbol.length(); i++) {
35 if (std::isalpha(Symbol[i]) || std::isdigit(Symbol[i]) || Symbol[i] == '_') {
36 // nothing
37 } else {
38 Symbol[i] == '_';
41 return Symbol;
44 String float_to_string(float value)
46 if (value < 0.0f || value > 1.0f) {
47 std::cerr << "WARNING - Parameter uses out-of-bounds default value -> " << value << std::endl;
49 String string(value);
50 if (!string.contains(".")) {
51 string += ".0";
53 return string;
56 String get_uri()
58 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":" JucePlugin_VersionString).replace(" ", "_");
61 String get_juce_ui_uri()
63 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":JUCE-Native-UI").replace(" ", "_");
66 String get_external_ui_uri()
68 return String("urn:" JucePlugin_Manufacturer ":" JucePlugin_Name ":JUCE-External-UI").replace(" ", "_");
71 String get_binary_name()
73 return String(JucePlugin_Name).replace(" ", "_");
76 String get_plugin_type()
78 String ptype;
80 switch (JucePlugin_VSTCategory) {
81 case kPlugCategSynth:
82 ptype += "lv2:InstrumentPlugin";
83 break;
84 case kPlugCategAnalysis:
85 ptype += "lv2:AnalyserPlugin";
86 break;
87 case kPlugCategMastering:
88 ptype += "lv2:DynamicsPlugin";
89 break;
90 case kPlugCategSpacializer:
91 ptype += "lv2:SpatialPlugin";
92 break;
93 case kPlugCategRoomFx:
94 ptype += "lv2:ModulatorPlugin";
95 break;
96 case kPlugCategRestoration:
97 ptype += "lv2:UtilityPlugin";
98 break;
99 case kPlugCategGenerator:
100 ptype += "lv2:GeneratorPlugin";
101 break;
104 if (ptype.isNotEmpty()) {
105 ptype += ", ";
108 ptype += "lv2:Plugin";
109 return ptype;
112 String get_manifest_ttl(String URI, String Binary)
114 String manifest;
115 manifest += "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
116 manifest += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
117 manifest += "\n";
118 manifest += "<" + URI + ">\n";
119 manifest += " a lv2:Plugin ;\n";
120 manifest += " lv2:binary <" + Binary + ".so> ;\n";
121 manifest += " rdfs:seeAlso <" + Binary +".ttl> .\n";
122 return manifest;
125 String get_plugin_ttl(String URI, String Binary)
127 AudioProcessor* filter = createPluginFilter();
129 String plugin;
130 plugin += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
131 //plugin += "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n";
132 //plugin += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
133 plugin += "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
134 plugin += "@prefix lv2ev: <http://lv2plug.in/ns/ext/event#> .\n";
135 plugin += "@prefix lv2ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
136 plugin += "\n";
138 if (filter->hasEditor()) {
139 plugin += "<" + get_external_ui_uri() + ">\n";
140 plugin += " a lv2ui:external ;\n";
141 plugin += " lv2ui:binary <" + Binary + ".so> .\n";
142 plugin += "<" + get_juce_ui_uri() + ">\n";
143 plugin += " a lv2ui:JUCEUI ;\n";
144 plugin += " lv2ui:binary <" + Binary + ".so> .\n";
145 plugin += "\n";
148 plugin += "<" + URI + ">\n";
149 plugin += " a " + get_plugin_type() + " ;\n";
151 if (filter->hasEditor()) {
152 plugin += " lv2ui:ui <" + get_external_ui_uri() + ">;\n";
153 //plugin += " lv2ui:ui <" + get_juce_ui_uri() + ">;\n"; // FIXME - how to handle 2 UIs?
156 plugin += "\n";
158 uint32_t i, port_index = 0;
160 #if JucePlugin_WantsMidiInput
161 plugin += " lv2:port [\n";
162 plugin += " a lv2:InputPort, lv2ev:EventPort;\n";
163 plugin += " lv2ev:supportsEvent <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
164 plugin += " lv2:index " + String(port_index) + ";\n";
165 plugin += " lv2:symbol \"midi_in\";\n";
166 plugin += " lv2:name \"MIDI Input\";\n";
167 plugin += " ] ;\n\n";
168 port_index++;
169 #endif
171 #if JucePlugin_ProducesMidiOutput
172 plugin += " lv2:port [\n";
173 plugin += " a lv2:OutputPort, lv2ev:EventPort;\n";
174 plugin += " lv2ev:supportsEvent <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
175 plugin += " lv2:index " + String(port_index) + ";\n";
176 plugin += " lv2:symbol \"midi_out\";\n";
177 plugin += " lv2:name \"MIDI Output\";\n";
178 plugin += " ] ;\n\n";
179 port_index++;
180 #endif
182 for (i=0; i<JucePlugin_MaxNumInputChannels; i++) {
183 if (i == 0) {
184 plugin += " lv2:port [\n";
185 } else {
186 plugin += " [\n";
189 plugin += " a lv2:InputPort, lv2:AudioPort;\n";
190 //plugin += " lv2:datatype lv2:float;\n";
191 plugin += " lv2:index " + String(port_index) + ";\n";
192 plugin += " lv2:symbol \"audio_in_" + String(i+1) + "\";\n";
193 plugin += " lv2:name \"Audio Input " + String(i+1) + "\";\n";
195 if (i == JucePlugin_MaxNumInputChannels-1) {
196 plugin += " ] ;\n\n";
197 } else {
198 plugin += " ],\n";
201 port_index++;
204 for (i=0; i<JucePlugin_MaxNumOutputChannels; i++) {
205 if (i == 0) {
206 plugin += " lv2:port [\n";
207 } else {
208 plugin += " [\n";
211 plugin += " a lv2:OutputPort, lv2:AudioPort;\n";
212 //plugin += " lv2:datatype lv2:float;\n";
213 plugin += " lv2:index " + String(port_index) + ";\n";
214 plugin += " lv2:symbol \"audio_out_" + String(i+1) + "\";\n";
215 plugin += " lv2:name \"Audio Output " + String(i+1) + "\";\n";
217 if (i == JucePlugin_MaxNumOutputChannels-1) {
218 plugin += " ] ;\n\n";
219 } else {
220 plugin += " ],\n";
223 port_index++;
226 for (i=0; i < filter->getNumParameters(); i++) {
227 if (i == 0) {
228 plugin += " lv2:port [\n";
229 } else {
230 plugin += " [\n";
233 plugin += " a lv2:InputPort;\n";
234 plugin += " a lv2:ControlPort;\n";
235 //plugin += " lv2:datatype lv2:float;\n";
236 plugin += " lv2:index " + String(port_index) + ";\n";
237 plugin += " lv2:symbol \"" + name_to_symbol(filter->getParameterName(i)) + "\";\n";
238 plugin += " lv2:name \"" + filter->getParameterName(i) + "\";\n";
239 plugin += " lv2:default " + float_to_string(filter->getParameter(i)) + ";\n";
240 plugin += " lv2:minimum 0.0;\n";
241 plugin += " lv2:maximum 1.0;\n";
242 // TODO - units
244 if (i == filter->getNumParameters()-1) {
245 plugin += " ] ;\n\n";
246 } else {
247 plugin += " ],\n";
250 port_index++;
253 if (filter->getNumParameters() > 0) {
254 plugin += "\n";
257 plugin += " doap:name \"" + String(JucePlugin_Name) + "\" ;\n";
258 plugin += " doap:creator \"" + String(JucePlugin_Manufacturer) + "\" .\n";
260 delete filter;
261 return plugin;
264 int main(int argc, char *argv[])
266 String URI = get_uri();
267 String Binary = get_binary_name();
268 String BinaryTTL = Binary + ".ttl";
270 std::cout << "Writing manifest.ttl...";
271 std::fstream manifest("manifest.ttl", std::ios::out);
272 manifest << get_manifest_ttl(URI, Binary) << std::endl;
273 manifest.close();
274 std::cout << " done!" << std::endl;
276 std::cout << "Writing " << BinaryTTL;
277 std::fstream plugin(BinaryTTL.toUTF8(), std::ios::out);
278 plugin << get_plugin_ttl(URI, Binary) << std::endl;
279 plugin.close();
280 std::cout << " done!" << std::endl;
282 return 0;