DISTRHO Plugin Framework
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

711 lines
27KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2017 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "DistrhoPluginInternal.hpp"
  17. #include "lv2/atom.h"
  18. #include "lv2/buf-size.h"
  19. #include "lv2/data-access.h"
  20. #include "lv2/instance-access.h"
  21. #include "lv2/midi.h"
  22. #include "lv2/options.h"
  23. #include "lv2/port-props.h"
  24. #include "lv2/presets.h"
  25. #include "lv2/resize-port.h"
  26. #include "lv2/state.h"
  27. #include "lv2/time.h"
  28. #include "lv2/ui.h"
  29. #include "lv2/units.h"
  30. #include "lv2/urid.h"
  31. #include "lv2/worker.h"
  32. #include "lv2/lv2_kxstudio_properties.h"
  33. #include "lv2/lv2_programs.h"
  34. #include <fstream>
  35. #include <iostream>
  36. #ifndef DISTRHO_PLUGIN_URI
  37. # error DISTRHO_PLUGIN_URI undefined!
  38. #endif
  39. #ifndef DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE
  40. # define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048
  41. #endif
  42. #ifndef DISTRHO_PLUGIN_USES_MODGUI
  43. # define DISTRHO_PLUGIN_USES_MODGUI 0
  44. #endif
  45. #if DISTRHO_PLUGIN_HAS_EMBED_UI
  46. # if DISTRHO_OS_HAIKU
  47. # define DISTRHO_LV2_UI_TYPE "BeUI"
  48. # elif DISTRHO_OS_MAC
  49. # define DISTRHO_LV2_UI_TYPE "CocoaUI"
  50. # elif DISTRHO_OS_WINDOWS
  51. # define DISTRHO_LV2_UI_TYPE "WindowsUI"
  52. # else
  53. # define DISTRHO_LV2_UI_TYPE "X11UI"
  54. # endif
  55. #else
  56. # define DISTRHO_LV2_UI_TYPE "UI"
  57. #endif
  58. #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
  59. #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_WANT_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
  60. // -----------------------------------------------------------------------
  61. DISTRHO_PLUGIN_EXPORT
  62. void lv2_generate_ttl(const char* const basename)
  63. {
  64. USE_NAMESPACE_DISTRHO
  65. // Dummy plugin to get data from
  66. d_lastBufferSize = 512;
  67. d_lastSampleRate = 44100.0;
  68. PluginExporter plugin;
  69. d_lastBufferSize = 0;
  70. d_lastSampleRate = 0.0;
  71. String pluginDLL(basename);
  72. String pluginTTL(pluginDLL + ".ttl");
  73. #if DISTRHO_PLUGIN_HAS_UI
  74. String pluginUI(pluginDLL);
  75. # if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  76. pluginUI.truncate(pluginDLL.rfind("_dsp"));
  77. pluginUI += "_ui";
  78. const String uiTTL(pluginUI + ".ttl");
  79. # endif
  80. #endif
  81. // ---------------------------------------------
  82. {
  83. std::cout << "Writing manifest.ttl..."; std::cout.flush();
  84. std::fstream manifestFile("manifest.ttl", std::ios::out);
  85. String manifestString;
  86. manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  87. manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  88. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  89. manifestString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n";
  90. #endif
  91. #if DISTRHO_PLUGIN_HAS_UI
  92. manifestString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
  93. #endif
  94. manifestString += "\n";
  95. manifestString += "<" DISTRHO_PLUGIN_URI ">\n";
  96. manifestString += " a lv2:Plugin ;\n";
  97. manifestString += " lv2:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n";
  98. #if DISTRHO_PLUGIN_USES_MODGUI
  99. manifestString += " rdfs:seeAlso <" + pluginTTL + "> ,\n";
  100. manifestString += " <modgui.ttl> .\n";
  101. #else
  102. manifestString += " rdfs:seeAlso <" + pluginTTL + "> .\n";
  103. #endif
  104. manifestString += "\n";
  105. #if DISTRHO_PLUGIN_HAS_UI
  106. manifestString += "<" DISTRHO_UI_URI ">\n";
  107. manifestString += " a ui:" DISTRHO_LV2_UI_TYPE " ;\n";
  108. manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n";
  109. # if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  110. manifestString += "\n";
  111. manifestString += " lv2:extensionData ui:idleInterface ,\n";
  112. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  113. manifestString += " ui:showInterface ,\n";
  114. manifestString += " <" LV2_PROGRAMS__Interface "> ;\n";
  115. # else
  116. manifestString += " ui:showInterface ;\n";
  117. # endif
  118. manifestString += "\n";
  119. # if DISTRHO_PLUGIN_HAS_EMBED_UI
  120. manifestString += " lv2:optionalFeature ui:noUserResize ,\n";
  121. manifestString += " ui:resize ,\n";
  122. manifestString += " ui:touch ;\n";
  123. manifestString += "\n";
  124. # endif
  125. manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n";
  126. manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n";
  127. manifestString += " <" LV2_OPTIONS__options "> ,\n";
  128. manifestString += " <" LV2_URID__map "> .\n";
  129. # else
  130. manifestString += " rdfs:seeAlso <" + uiTTL + "> .\n";
  131. # endif
  132. manifestString += "\n";
  133. #endif
  134. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  135. const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#");
  136. char strBuf[0xff+1];
  137. strBuf[0xff] = '\0';
  138. String presetString;
  139. // Presets
  140. for (uint32_t i = 0; i < plugin.getProgramCount(); ++i)
  141. {
  142. std::snprintf(strBuf, 0xff, "%03i", i+1);
  143. presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n";
  144. presetString += " a pset:Preset ;\n";
  145. presetString += " lv2:appliesTo <" DISTRHO_PLUGIN_URI "> ;\n";
  146. presetString += " rdfs:label \"" + plugin.getProgramName(i) + "\" ;\n";
  147. presetString += " rdfs:seeAlso <presets.ttl> .\n";
  148. presetString += "\n";
  149. manifestString += presetString;
  150. }
  151. #endif
  152. manifestFile << manifestString << std::endl;
  153. manifestFile.close();
  154. std::cout << " done!" << std::endl;
  155. }
  156. // ---------------------------------------------
  157. {
  158. std::cout << "Writing " << pluginTTL << "..."; std::cout.flush();
  159. std::fstream pluginFile(pluginTTL, std::ios::out);
  160. String pluginString;
  161. // header
  162. #if DISTRHO_LV2_USE_EVENTS_IN
  163. pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
  164. #endif
  165. pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
  166. pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
  167. pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  168. #ifdef DISTRHO_PLUGIN_BRAND
  169. pluginString += "@prefix mod: <http://moddevices.com/ns/mod#> .\n";
  170. #endif
  171. pluginString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  172. pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n";
  173. #if DISTRHO_PLUGIN_HAS_UI
  174. pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
  175. #endif
  176. pluginString += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n";
  177. pluginString += "\n";
  178. // plugin
  179. pluginString += "<" DISTRHO_PLUGIN_URI ">\n";
  180. #ifdef DISTRHO_PLUGIN_LV2_CATEGORY
  181. pluginString += " a " DISTRHO_PLUGIN_LV2_CATEGORY ", lv2:Plugin ;\n";
  182. #elif DISTRHO_PLUGIN_IS_SYNTH
  183. pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n";
  184. #else
  185. pluginString += " a lv2:Plugin ;\n";
  186. #endif
  187. pluginString += "\n";
  188. // extensionData
  189. pluginString += " lv2:extensionData <" LV2_STATE__interface "> ";
  190. #if DISTRHO_PLUGIN_WANT_STATE
  191. pluginString += ",\n <" LV2_OPTIONS__interface "> ";
  192. pluginString += ",\n <" LV2_WORKER__interface "> ";
  193. #endif
  194. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  195. pluginString += ",\n <" LV2_PROGRAMS__Interface "> ";
  196. #endif
  197. pluginString += ";\n\n";
  198. // optionalFeatures
  199. #if DISTRHO_PLUGIN_IS_RT_SAFE
  200. pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
  201. pluginString += " <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
  202. #else
  203. pluginString += " lv2:optionalFeature <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
  204. #endif
  205. pluginString += "\n";
  206. // requiredFeatures
  207. pluginString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ";
  208. pluginString += ",\n <" LV2_URID__map "> ";
  209. #if DISTRHO_PLUGIN_WANT_STATE
  210. pluginString += ",\n <" LV2_WORKER__schedule "> ";
  211. #endif
  212. pluginString += ";\n\n";
  213. // UI
  214. #if DISTRHO_PLUGIN_HAS_UI
  215. pluginString += " ui:ui <" DISTRHO_UI_URI "> ;\n";
  216. pluginString += "\n";
  217. #endif
  218. {
  219. uint32_t portIndex = 0;
  220. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  221. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex)
  222. {
  223. const AudioPort& port(plugin.getAudioPort(true, i));
  224. if (i == 0)
  225. pluginString += " lv2:port [\n";
  226. else
  227. pluginString += " [\n";
  228. if (port.hints & kAudioPortIsCV)
  229. pluginString += " a lv2:InputPort, lv2:CVPort ;\n";
  230. else
  231. pluginString += " a lv2:InputPort, lv2:AudioPort ;\n";
  232. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  233. pluginString += " lv2:symbol \"lv2_" + port.symbol + "\" ;\n";
  234. pluginString += " lv2:name \"" + port.name + "\" ;\n";
  235. if (port.hints & kAudioPortIsSidechain)
  236. pluginString += " lv2:portProperty lv2:isSideChain;\n";
  237. if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS)
  238. pluginString += " ] ;\n";
  239. else
  240. pluginString += " ] ,\n";
  241. }
  242. pluginString += "\n";
  243. #endif
  244. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  245. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex)
  246. {
  247. const AudioPort& port(plugin.getAudioPort(false, i));
  248. if (i == 0)
  249. pluginString += " lv2:port [\n";
  250. else
  251. pluginString += " [\n";
  252. if (port.hints & kAudioPortIsCV)
  253. pluginString += " a lv2:OutputPort, lv2:CVPort ;\n";
  254. else
  255. pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n";
  256. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  257. pluginString += " lv2:symbol \"lv2_" + port.symbol + "\" ;\n";
  258. pluginString += " lv2:name \"" + port.name + "\" ;\n";
  259. if (port.hints & kAudioPortIsSidechain)
  260. pluginString += " lv2:portProperty lv2:isSideChain;\n";
  261. if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS)
  262. pluginString += " ] ;\n";
  263. else
  264. pluginString += " ] ,\n";
  265. }
  266. pluginString += "\n";
  267. #endif
  268. #if DISTRHO_LV2_USE_EVENTS_IN
  269. pluginString += " lv2:port [\n";
  270. pluginString += " a lv2:InputPort, atom:AtomPort ;\n";
  271. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  272. pluginString += " lv2:name \"Events Input\" ;\n";
  273. pluginString += " lv2:symbol \"lv2_events_in\" ;\n";
  274. pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n";
  275. pluginString += " atom:bufferType atom:Sequence ;\n";
  276. # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
  277. pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
  278. # endif
  279. # if DISTRHO_PLUGIN_WANT_MIDI_INPUT
  280. pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
  281. # endif
  282. # if DISTRHO_PLUGIN_WANT_TIMEPOS
  283. pluginString += " atom:supports <" LV2_TIME__Position "> ;\n";
  284. # endif
  285. pluginString += " ] ;\n\n";
  286. ++portIndex;
  287. #endif
  288. #if DISTRHO_LV2_USE_EVENTS_OUT
  289. pluginString += " lv2:port [\n";
  290. pluginString += " a lv2:OutputPort, atom:AtomPort ;\n";
  291. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  292. pluginString += " lv2:name \"Events Output\" ;\n";
  293. pluginString += " lv2:symbol \"lv2_events_out\" ;\n";
  294. pluginString += " rsz:minimumSize " + String(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n";
  295. pluginString += " atom:bufferType atom:Sequence ;\n";
  296. # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
  297. pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
  298. # endif
  299. # if DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
  300. pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
  301. # endif
  302. pluginString += " ] ;\n\n";
  303. ++portIndex;
  304. #endif
  305. #if DISTRHO_PLUGIN_WANT_LATENCY
  306. pluginString += " lv2:port [\n";
  307. pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
  308. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  309. pluginString += " lv2:name \"Latency\" ;\n";
  310. pluginString += " lv2:symbol \"lv2_latency\" ;\n";
  311. pluginString += " lv2:designation lv2:latency ;\n";
  312. pluginString += " lv2:portProperty lv2:reportsLatency, lv2:integer, <" LV2_PORT_PROPS__notOnGUI "> ;\n";
  313. pluginString += " ] ;\n\n";
  314. ++portIndex;
  315. #endif
  316. for (uint32_t i=0, count=plugin.getParameterCount(); i < count; ++i, ++portIndex)
  317. {
  318. if (i == 0)
  319. pluginString += " lv2:port [\n";
  320. else
  321. pluginString += " [\n";
  322. if (plugin.isParameterOutput(i))
  323. pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
  324. else
  325. pluginString += " a lv2:InputPort, lv2:ControlPort ;\n";
  326. pluginString += " lv2:index " + String(portIndex) + " ;\n";
  327. bool designated = false;
  328. // designation
  329. if (! plugin.isParameterOutput(i))
  330. {
  331. switch (plugin.getParameterDesignation(i))
  332. {
  333. case kParameterDesignationNull:
  334. break;
  335. case kParameterDesignationBypass:
  336. designated = true;
  337. pluginString += " lv2:name \"Enabled\" ;\n";
  338. pluginString += " lv2:symbol \"lv2_enabled\" ;\n";
  339. pluginString += " lv2:default 1 ;\n";
  340. pluginString += " lv2:minimum 0 ;\n";
  341. pluginString += " lv2:maximum 1 ;\n";
  342. pluginString += " lv2:portProperty lv2:toggled , lv2:integer ;\n";
  343. pluginString += " lv2:designation lv2:enabled ;\n";
  344. break;
  345. }
  346. }
  347. // name and symbol
  348. if (! designated)
  349. {
  350. pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n";
  351. String symbol(plugin.getParameterSymbol(i));
  352. if (symbol.isEmpty())
  353. symbol = "lv2_port_" + String(portIndex-1);
  354. pluginString += " lv2:symbol \"" + symbol + "\" ;\n";
  355. }
  356. // ranges
  357. if (! designated)
  358. {
  359. const ParameterRanges& ranges(plugin.getParameterRanges(i));
  360. if (plugin.getParameterHints(i) & kParameterIsInteger)
  361. {
  362. if (! plugin.isParameterOutput(i))
  363. pluginString += " lv2:default " + String(int(plugin.getParameterValue(i))) + " ;\n";
  364. pluginString += " lv2:minimum " + String(int(ranges.min)) + " ;\n";
  365. pluginString += " lv2:maximum " + String(int(ranges.max)) + " ;\n";
  366. }
  367. else
  368. {
  369. if (! plugin.isParameterOutput(i))
  370. pluginString += " lv2:default " + String(plugin.getParameterValue(i)) + " ;\n";
  371. pluginString += " lv2:minimum " + String(ranges.min) + " ;\n";
  372. pluginString += " lv2:maximum " + String(ranges.max) + " ;\n";
  373. }
  374. }
  375. // unit
  376. if (! designated)
  377. {
  378. const String& unit(plugin.getParameterUnit(i));
  379. if (! unit.isEmpty())
  380. {
  381. if (unit == "db" || unit == "dB")
  382. {
  383. pluginString += " unit:unit unit:db ;\n";
  384. }
  385. else if (unit == "hz" || unit == "Hz")
  386. {
  387. pluginString += " unit:unit unit:hz ;\n";
  388. }
  389. else if (unit == "khz" || unit == "kHz")
  390. {
  391. pluginString += " unit:unit unit:khz ;\n";
  392. }
  393. else if (unit == "mhz" || unit == "mHz")
  394. {
  395. pluginString += " unit:unit unit:mhz ;\n";
  396. }
  397. else if (unit == "ms")
  398. {
  399. pluginString += " unit:unit unit:ms ;\n";
  400. }
  401. else if (unit == "s")
  402. {
  403. pluginString += " unit:unit unit:s ;\n";
  404. }
  405. else if (unit == "%")
  406. {
  407. pluginString += " unit:unit unit:pc ;\n";
  408. }
  409. else
  410. {
  411. pluginString += " unit:unit [\n";
  412. pluginString += " rdfs:label \"" + unit + "\" ;\n";
  413. pluginString += " unit:symbol \"" + unit + "\" ;\n";
  414. pluginString += " unit:render \"%f " + unit + "\" ;\n";
  415. pluginString += " ] ;\n";
  416. }
  417. }
  418. }
  419. // hints
  420. if (! designated)
  421. {
  422. const uint32_t hints(plugin.getParameterHints(i));
  423. if (hints & kParameterIsBoolean)
  424. pluginString += " lv2:portProperty lv2:toggled ;\n";
  425. if (hints & kParameterIsInteger)
  426. pluginString += " lv2:portProperty lv2:integer ;\n";
  427. if (hints & kParameterIsLogarithmic)
  428. pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n";
  429. if ((hints & kParameterIsAutomable) == 0 && ! plugin.isParameterOutput(i))
  430. {
  431. pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n";
  432. pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n";
  433. }
  434. }
  435. if (i+1 == count)
  436. pluginString += " ] ;\n\n";
  437. else
  438. pluginString += " ] ,\n";
  439. }
  440. }
  441. // comment
  442. {
  443. const String comment(plugin.getDescription());
  444. if (comment.isNotEmpty())
  445. pluginString += " rdfs:comment \"\"\"\n" + comment + "\n\"\"\" ;\n\n";
  446. }
  447. #ifdef DISTRHO_PLUGIN_BRAND
  448. // MOD
  449. pluginString += " mod:brand \"" DISTRHO_PLUGIN_BRAND "\" ;\n";
  450. pluginString += " mod:label \"" DISTRHO_PLUGIN_NAME "\" ;\n\n";
  451. #endif
  452. // name
  453. pluginString += " doap:name \"" + String(plugin.getName()) + "\" ;\n";
  454. // license
  455. {
  456. const String license(plugin.getLicense());
  457. if (license.contains("://"))
  458. pluginString += " doap:license <" + license + "> ;\n\n";
  459. else
  460. pluginString += " doap:license \"" + license + "\" ;\n\n";
  461. }
  462. // developer
  463. {
  464. const String homepage(plugin.getHomePage());
  465. pluginString += " doap:maintainer [\n";
  466. pluginString += " foaf:name \"" + String(plugin.getMaker()) + "\" ;\n";
  467. if (homepage.isNotEmpty())
  468. pluginString += " foaf:homepage <" + homepage + "> ;\n";
  469. pluginString += " ] ;\n\n";
  470. }
  471. {
  472. const uint32_t version(plugin.getVersion());
  473. const uint32_t majorVersion = (version & 0xFF0000) >> 16;
  474. const uint32_t microVersion = (version & 0x00FF00) >> 8;
  475. /* */ uint32_t minorVersion = (version & 0x0000FF) >> 0;
  476. // NOTE: LV2 ignores 'major' version and says 0 for minor is pre-release/unstable.
  477. if (majorVersion > 0)
  478. minorVersion += 2;
  479. pluginString += " lv2:microVersion " + String(microVersion) + " ;\n";
  480. pluginString += " lv2:minorVersion " + String(minorVersion) + " .\n";
  481. }
  482. pluginFile << pluginString << std::endl;
  483. pluginFile.close();
  484. std::cout << " done!" << std::endl;
  485. }
  486. // ---------------------------------------------
  487. #if DISTRHO_PLUGIN_HAS_UI && ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  488. {
  489. std::cout << "Writing " << uiTTL << "..."; std::cout.flush();
  490. std::fstream uiFile(uiTTL, std::ios::out);
  491. String uiString;
  492. uiString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  493. uiString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
  494. uiString += "\n";
  495. uiString += "<" DISTRHO_UI_URI ">\n";
  496. uiString += " lv2:extensionData ui:idleInterface ,\n";
  497. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  498. uiString += " ui:showInterface ,\n";
  499. uiString += " <" LV2_PROGRAMS__Interface "> ;\n";
  500. # else
  501. uiString += " ui:showInterface ;\n";
  502. # endif
  503. uiString += "\n";
  504. # if DISTRHO_PLUGIN_HAS_EMBED_UI
  505. uiString += " lv2:optionalFeature ui:noUserResize ,\n";
  506. uiString += " ui:resize ,\n";
  507. uiString += " ui:touch ;\n";
  508. uiString += "\n";
  509. # endif
  510. uiString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n";
  511. uiString += " <" LV2_URID__map "> .\n";
  512. uiFile << uiString << std::endl;
  513. uiFile.close();
  514. std::cout << " done!" << std::endl;
  515. }
  516. #endif
  517. // ---------------------------------------------
  518. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  519. {
  520. std::cout << "Writing presets.ttl..."; std::cout.flush();
  521. std::fstream presetsFile("presets.ttl", std::ios::out);
  522. String presetsString;
  523. presetsString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  524. presetsString += "@prefix pset: <" LV2_PRESETS_PREFIX "> .\n";
  525. # if DISTRHO_PLUGIN_WANT_STATE
  526. presetsString += "@prefix state: <" LV2_STATE_PREFIX "> .\n";
  527. # endif
  528. presetsString += "\n";
  529. const uint32_t numParameters = plugin.getParameterCount();
  530. const uint32_t numPrograms = plugin.getProgramCount();
  531. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  532. const uint32_t numStates = plugin.getStateCount();
  533. # endif
  534. const String presetSeparator(std::strstr(DISTRHO_PLUGIN_URI, "#") != nullptr ? ":" : "#");
  535. char strBuf[0xff+1];
  536. strBuf[0xff] = '\0';
  537. String presetString;
  538. for (uint32_t i=0; i<numPrograms; ++i)
  539. {
  540. std::snprintf(strBuf, 0xff, "%03i", i+1);
  541. plugin.loadProgram(i);
  542. presetString = "<" DISTRHO_PLUGIN_URI + presetSeparator + "preset" + strBuf + ">\n";
  543. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  544. if (numParameters == 0 && numStates == 0)
  545. #else
  546. if (numParameters == 0)
  547. #endif
  548. {
  549. presetString += " .";
  550. presetsString += presetString;
  551. continue;
  552. }
  553. # if DISTRHO_PLUGIN_WANT_FULL_STATE
  554. presetString += " state:state [\n";
  555. for (uint32_t j=0; j<numStates; ++j)
  556. {
  557. const String key = plugin.getStateKey(j);
  558. const String value = plugin.getState(key);
  559. presetString += " <urn:distrho:" + key + ">";
  560. if (value.length() < 10)
  561. presetString += " \"" + value + "\" ;\n";
  562. else
  563. presetString += "\n\"\"\"\n" + value + "\n\"\"\" ;\n";
  564. }
  565. if (numParameters > 0)
  566. presetString += " ] ;\n\n";
  567. else
  568. presetString += " ] .\n\n";
  569. # endif
  570. bool firstParameter = true;
  571. for (uint32_t j=0; j <numParameters; ++j)
  572. {
  573. if (plugin.isParameterOutput(j))
  574. continue;
  575. if (firstParameter)
  576. {
  577. presetString += " lv2:port [\n";
  578. firstParameter = false;
  579. }
  580. else
  581. {
  582. presetString += " [\n";
  583. }
  584. presetString += " lv2:symbol \"" + plugin.getParameterSymbol(j) + "\" ;\n";
  585. if (plugin.getParameterHints(j) & kParameterIsInteger)
  586. presetString += " pset:value " + String(int(plugin.getParameterValue(j))) + " ;\n";
  587. else
  588. presetString += " pset:value " + String(plugin.getParameterValue(j)) + " ;\n";
  589. if (j+1 == numParameters || (j+2 == numParameters && plugin.isParameterOutput(j+1)))
  590. presetString += " ] .\n\n";
  591. else
  592. presetString += " ] ,\n";
  593. }
  594. presetsString += presetString;
  595. }
  596. presetsFile << presetsString << std::endl;
  597. presetsFile.close();
  598. std::cout << " done!" << std::endl;
  599. }
  600. #endif
  601. }