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