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.

754 lines
29KB

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