1 #include "SurgeLv2Wrapper.h"
2 #include "version.h"
3 #include <fstream>
4 #include <iomanip>
5
6 #if defined _WIN32
7 #define LV2_DLL_SUFFIX ".dll"
8 #define LV2_UI_TYPE "WindowsUI"
9 #elif defined __APPLE__
10 #define LV2_DLL_SUFFIX ".dylib"
11 #define LV2_UI_TYPE "CocoaUI"
12 #else
13 #define LV2_DLL_SUFFIX ".so"
14 #define LV2_UI_TYPE "X11UI"
15 #endif
16
17 static void writePrefix(std::ofstream &os);
18
19 LV2_SYMBOL_EXPORT
lv2_generate_ttl(const char * baseName)20 void lv2_generate_ttl(const char *baseName)
21 {
22 const LV2_Descriptor *desc = lv2_descriptor(0);
23 const LV2UI_Descriptor *uidesc = lv2ui_descriptor(0);
24
25 SurgeStorage::skipLoadWtAndPatch = true;
26
27 SurgeLv2Wrapper defaultInstance(44100.0);
28 SurgeSynthesizer *defaultSynth = defaultInstance.synthesizer();
29
30 {
31 std::ofstream osMan("manifest.ttl");
32 writePrefix(osMan);
33
34 osMan << "<" << desc->URI
35 << ">\n"
36 " a lv2:Plugin, lv2:InstrumentPlugin ;\n"
37 " lv2:binary <"
38 << baseName
39 << LV2_DLL_SUFFIX "> ;\n"
40 " rdfs:seeAlso <"
41 << baseName
42 << "_dsp.ttl> .\n"
43 "\n"
44 "<"
45 << uidesc->URI
46 << ">\n"
47 " a ui:" LV2_UI_TYPE " ;\n"
48 " ui:binary <"
49 << baseName
50 << LV2_DLL_SUFFIX "> ;\n"
51 " rdfs:seeAlso <"
52 << baseName << "_ui.ttl> .\n";
53 }
54
55 {
56 std::ofstream osDsp(baseName + std::string("_dsp.ttl"));
57 writePrefix(osDsp);
58
59 osDsp << "<" << desc->URI
60 << ">\n"
61 " doap:name \""
62 << stringProductName
63 << "\" ;\n"
64 " doap:license <https://www.gnu.org/licenses/gpl-3.0.en.html> ;\n"
65 " doap:maintainer [\n"
66 " foaf:name \""
67 << stringCompanyName
68 << "\" ;\n"
69 " foaf:homepage <"
70 << stringWebsite
71 << "> ;\n"
72 " ] ;\n"
73 " ui:ui <"
74 << uidesc->URI
75 << "> ;\n"
76 " lv2:optionalFeature lv2:hardRTCapable ;\n"
77 " lv2:requiredFeature urid:map ;\n"
78 " lv2:extensionData state:interface ;\n";
79
80 unsigned portIndex = 0;
81 osDsp << " lv2:port";
82 // parameters
83 for (unsigned pNth = 0; pNth < n_total_params; ++pNth)
84 {
85 if (portIndex > 0)
86 osDsp << " ,";
87
88 SurgeSynthesizer::ID did;
89 defaultSynth->fromDAWSideIndex(pNth, did);
90 parametermeta pMeta;
91 defaultSynth->getParameterMeta(did, pMeta);
92
93 char pName[256];
94 defaultSynth->getParameterName(did, pName);
95
96 std::string pSymbol;
97 int index = did.getSynthSideId();
98 if (index >= metaparam_offset)
99 {
100 pSymbol = "meta_cc" + std::to_string(index - metaparam_offset + 1);
101 }
102 else
103 {
104 auto *par = defaultSynth->storage.getPatch().param_ptr[index];
105 pSymbol = par->get_storage_name();
106 }
107
108 osDsp << " [\n"
109 " a lv2:InputPort, lv2:ControlPort ;\n"
110 " lv2:index "
111 << portIndex
112 << " ;\n"
113 " lv2:symbol \""
114 << pSymbol
115 << "\" ;\n"
116 " lv2:name \""
117 << pName
118 << "\" ;\n"
119 " lv2:default "
120 << std::fixed << std::setw(10) << std::setprecision(8)
121 << defaultSynth->getParameter01(did)
122 << " ;\n"
123 " lv2:minimum "
124 << std::fixed << std::setw(10) << std::setprecision(8) << pMeta.fmin
125 << " ;\n"
126 " lv2:maximum "
127 << std::fixed << std::setw(10) << std::setprecision(8) << pMeta.fmax
128 << " ;\n"
129 " ]";
130 ++portIndex;
131 }
132 // event input
133 {
134 if (portIndex > 0)
135 osDsp << " ,";
136 osDsp << " [\n"
137 " a lv2:InputPort, atom:AtomPort ;\n"
138 " lv2:index "
139 << portIndex
140 << " ;\n"
141 " lv2:symbol \"events_in\" ;\n"
142 " lv2:name \"Event input\" ;\n"
143 " rsz:minimumSize "
144 << SurgeLv2Wrapper::EventBufferSize
145 << " ;\n"
146 " atom:bufferType atom:Sequence ;\n"
147 " atom:supports midi:MidiEvent,\n"
148 " time:Position ;\n"
149 " ]";
150 ++portIndex;
151 }
152 // audio input
153 for (unsigned i = 0; i < SurgeLv2Wrapper::NumInputs; ++i, ++portIndex)
154 {
155 if (portIndex > 0)
156 osDsp << " ,";
157 osDsp << " [\n"
158 " a lv2:InputPort, lv2:AudioPort ;\n"
159 " lv2:index "
160 << portIndex
161 << " ;\n"
162 " lv2:symbol \"audio_in_"
163 << (i + 1)
164 << "\" ;\n"
165 " lv2:name \"Audio input "
166 << (i + 1)
167 << "\" ;\n"
168 " lv2:portProperty lv2:connectionOptional ;\n"
169 " ]";
170 }
171 // audio output
172 for (unsigned i = 0; i < SurgeLv2Wrapper::NumOutputs; ++i, ++portIndex)
173 {
174 if (portIndex > 0)
175 osDsp << " ,";
176 osDsp << " [\n"
177 " a lv2:OutputPort, lv2:AudioPort ;\n"
178 " lv2:index "
179 << portIndex
180 << " ;\n"
181 " lv2:symbol \"audio_out_"
182 << (i + 1)
183 << "\" ;\n"
184 " lv2:name \"Audio output "
185 << (i + 1)
186 << "\" ;\n"
187 " ]";
188 }
189 osDsp << " ;\n";
190
191 // TODO LV2: implement an adequate version number scheme. For now, make it the last two
192 // (so 1.6.2 gets 6 2)
193 osDsp << " lv2:minorVersion " << Surge::Build::SubVersionInt
194 << " ;\n"
195 " lv2:microVersion "
196 << Surge::Build::ReleaseNumberStr << " .\n";
197 }
198
199 {
200 std::ofstream osUi(baseName + std::string("_ui.ttl"));
201 writePrefix(osUi);
202
203 osUi << "<" << uidesc->URI
204 << ">\n"
205 " lv2:optionalFeature ui:parent,\n"
206 " ui:resize,\n"
207 " ui:noUserResize ;\n"
208 " lv2:requiredFeature ui:idleInterface ,\n"
209 " <" LV2_INSTANCE_ACCESS_URI "> ;\n"
210 " opts:supportedOption ui:scaleFactor ;\n"
211 " lv2:extensionData ui:idleInterface .\n";
212 }
213 }
214
writePrefix(std::ofstream & os)215 static void writePrefix(std::ofstream &os)
216 {
217 os << "@prefix lv2: <" LV2_CORE_PREFIX "> .\n"
218 "@prefix opts: <" LV2_OPTIONS_PREFIX "> .\n"
219 "@prefix ui: <" LV2_UI_PREFIX "> .\n"
220 "@prefix atom: <" LV2_ATOM_PREFIX "> .\n"
221 "@prefix urid: <" LV2_URID_PREFIX "> .\n"
222 "@prefix unit: <" LV2_UNITS_PREFIX "> .\n"
223 "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n"
224 "@prefix midi: <" LV2_MIDI_PREFIX "> .\n"
225 "@prefix time: <" LV2_TIME_PREFIX "> .\n"
226 "@prefix state: <" LV2_STATE_PREFIX "> .\n"
227 "@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .\n"
228 "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n"
229 "@prefix doap: <http://usefulinc.com/ns/doap#> .\n"
230 "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n"
231 "\n";
232 }
233