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.

411 lines
17KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2014 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/resize-port.h"
  25. #include "lv2/state.h"
  26. #include "lv2/time.h"
  27. #include "lv2/ui.h"
  28. #include "lv2/units.h"
  29. #include "lv2/urid.h"
  30. #include "lv2/worker.h"
  31. #include "lv2/lv2_kxstudio_properties.h"
  32. #include "lv2/lv2_programs.h"
  33. #include <fstream>
  34. #include <iostream>
  35. #ifndef DISTRHO_PLUGIN_URI
  36. # error DISTRHO_PLUGIN_URI undefined!
  37. #endif
  38. #ifndef DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE
  39. # define DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE 2048
  40. #endif
  41. #if DISTRHO_PLUGIN_HAS_UI && ! defined(HAVE_DGL)
  42. # undef DISTRHO_PLUGIN_HAS_UI
  43. # define DISTRHO_PLUGIN_HAS_UI 0
  44. #endif
  45. #define DISTRHO_LV2_USE_EVENTS_IN (DISTRHO_PLUGIN_HAS_MIDI_INPUT || DISTRHO_PLUGIN_WANT_TIMEPOS || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
  46. #define DISTRHO_LV2_USE_EVENTS_OUT (DISTRHO_PLUGIN_HAS_MIDI_OUTPUT || (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI))
  47. // -----------------------------------------------------------------------
  48. DISTRHO_PLUGIN_EXPORT
  49. void lv2_generate_ttl(const char* const basename)
  50. {
  51. USE_NAMESPACE_DISTRHO
  52. // Dummy plugin to get data from
  53. d_lastBufferSize = 512;
  54. d_lastSampleRate = 44100.0;
  55. PluginExporter plugin;
  56. d_lastBufferSize = 0;
  57. d_lastSampleRate = 0.0;
  58. d_string pluginDLL(basename);
  59. d_string pluginTTL(pluginDLL + ".ttl");
  60. // ---------------------------------------------
  61. {
  62. std::cout << "Writing manifest.ttl..."; std::cout.flush();
  63. std::fstream manifestFile("manifest.ttl", std::ios::out);
  64. d_string manifestString;
  65. manifestString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  66. manifestString += "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
  67. #if DISTRHO_PLUGIN_HAS_UI
  68. manifestString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
  69. #endif
  70. manifestString += "\n";
  71. manifestString += "<" DISTRHO_PLUGIN_URI ">\n";
  72. manifestString += " a lv2:Plugin ;\n";
  73. manifestString += " lv2:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n";
  74. manifestString += " rdfs:seeAlso <" + pluginTTL + "> .\n";
  75. manifestString += "\n";
  76. #if DISTRHO_PLUGIN_HAS_UI
  77. manifestString += "<" DISTRHO_UI_URI ">\n";
  78. # if DISTRHO_OS_HAIKU
  79. manifestString += " a ui:BeUI ;\n";
  80. # elif DISTRHO_OS_MAC
  81. manifestString += " a ui:CocoaUI ;\n";
  82. # elif DISTRHO_OS_WINDOWS
  83. manifestString += " a ui:WindowsUI ;\n";
  84. # else
  85. manifestString += " a ui:X11UI ;\n";
  86. # endif
  87. # if ! DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  88. d_string pluginUI(pluginDLL);
  89. pluginUI.truncate(pluginDLL.rfind("_dsp"));
  90. pluginUI += "_ui";
  91. manifestString += " ui:binary <" + pluginUI + "." DISTRHO_DLL_EXTENSION "> ;\n";
  92. # else
  93. manifestString += " ui:binary <" + pluginDLL + "." DISTRHO_DLL_EXTENSION "> ;\n";
  94. #endif
  95. manifestString += " lv2:extensionData ui:idleInterface ,\n";
  96. # if DISTRHO_PLUGIN_WANT_PROGRAMS
  97. manifestString += " ui:showInterface ,\n";
  98. manifestString += " <" LV2_PROGRAMS__Interface "> ;\n";
  99. # else
  100. manifestString += " ui:showInterface ;\n";
  101. # endif
  102. manifestString += " lv2:optionalFeature ui:noUserResize ,\n";
  103. manifestString += " ui:resize ,\n";
  104. manifestString += " ui:touch ;\n";
  105. # if DISTRHO_PLUGIN_WANT_DIRECT_ACCESS
  106. manifestString += " lv2:requiredFeature <" LV2_DATA_ACCESS_URI "> ,\n";
  107. manifestString += " <" LV2_INSTANCE_ACCESS_URI "> ,\n";
  108. manifestString += " <" LV2_OPTIONS__options "> ,\n";
  109. # else
  110. manifestString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ,\n";
  111. # endif
  112. manifestString += " <" LV2_URID__map "> .\n";
  113. #endif
  114. manifestFile << manifestString << std::endl;
  115. manifestFile.close();
  116. std::cout << " done!" << std::endl;
  117. }
  118. // ---------------------------------------------
  119. {
  120. std::cout << "Writing " << pluginTTL << "..."; std::cout.flush();
  121. std::fstream pluginFile(pluginTTL, std::ios::out);
  122. d_string pluginString;
  123. // header
  124. #if DISTRHO_LV2_USE_EVENTS_IN
  125. pluginString += "@prefix atom: <" LV2_ATOM_PREFIX "> .\n";
  126. #endif
  127. pluginString += "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
  128. pluginString += "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
  129. pluginString += "@prefix lv2: <" LV2_CORE_PREFIX "> .\n";
  130. pluginString += "@prefix rsz: <" LV2_RESIZE_PORT_PREFIX "> .\n";
  131. #if DISTRHO_PLUGIN_HAS_UI
  132. pluginString += "@prefix ui: <" LV2_UI_PREFIX "> .\n";
  133. #endif
  134. pluginString += "@prefix unit: <" LV2_UNITS_PREFIX "> .\n";
  135. pluginString += "\n";
  136. // plugin
  137. pluginString += "<" DISTRHO_PLUGIN_URI ">\n";
  138. #if DISTRHO_PLUGIN_IS_SYNTH
  139. pluginString += " a lv2:InstrumentPlugin, lv2:Plugin ;\n";
  140. #else
  141. pluginString += " a lv2:Plugin ;\n";
  142. #endif
  143. pluginString += "\n";
  144. // extensionData
  145. pluginString += " lv2:extensionData <" LV2_STATE__interface "> ";
  146. #if DISTRHO_PLUGIN_WANT_STATE
  147. pluginString += ",\n <" LV2_OPTIONS__interface "> ";
  148. pluginString += ",\n <" LV2_WORKER__interface "> ";
  149. #endif
  150. #if DISTRHO_PLUGIN_WANT_PROGRAMS
  151. pluginString += ",\n <" LV2_PROGRAMS__Interface "> ";
  152. #endif
  153. pluginString += ";\n\n";
  154. // optionalFeatures
  155. #if DISTRHO_PLUGIN_IS_RT_SAFE
  156. pluginString += " lv2:optionalFeature <" LV2_CORE__hardRTCapable "> ,\n";
  157. pluginString += " <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
  158. #else
  159. pluginString += " lv2:optionalFeature <" LV2_BUF_SIZE__boundedBlockLength "> ;\n";
  160. #endif
  161. pluginString += "\n";
  162. // requiredFeatures
  163. pluginString += " lv2:requiredFeature <" LV2_OPTIONS__options "> ";
  164. pluginString += ",\n <" LV2_URID__map "> ";
  165. #if DISTRHO_PLUGIN_WANT_STATE
  166. pluginString += ",\n <" LV2_WORKER__schedule "> ";
  167. #endif
  168. pluginString += ";\n\n";
  169. // UI
  170. #if DISTRHO_PLUGIN_HAS_UI
  171. pluginString += " ui:ui <" DISTRHO_UI_URI "> ;\n";
  172. pluginString += "\n";
  173. #endif
  174. {
  175. uint32_t portIndex = 0;
  176. #if DISTRHO_PLUGIN_NUM_INPUTS > 0
  177. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_INPUTS; ++i, ++portIndex)
  178. {
  179. if (i == 0)
  180. pluginString += " lv2:port [\n";
  181. else
  182. pluginString += " [\n";
  183. pluginString += " a lv2:InputPort, lv2:AudioPort ;\n";
  184. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  185. pluginString += " lv2:symbol \"lv2_audio_in_" + d_string(i+1) + "\" ;\n";
  186. pluginString += " lv2:name \"Audio Input " + d_string(i+1) + "\" ;\n";
  187. if (i+1 == DISTRHO_PLUGIN_NUM_INPUTS)
  188. pluginString += " ] ;\n\n";
  189. else
  190. pluginString += " ] ,\n";
  191. }
  192. pluginString += "\n";
  193. #endif
  194. #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
  195. for (uint32_t i=0; i < DISTRHO_PLUGIN_NUM_OUTPUTS; ++i, ++portIndex)
  196. {
  197. if (i == 0)
  198. pluginString += " lv2:port [\n";
  199. else
  200. pluginString += " [\n";
  201. pluginString += " a lv2:OutputPort, lv2:AudioPort ;\n";
  202. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  203. pluginString += " lv2:symbol \"lv2_audio_out_" + d_string(i+1) + "\" ;\n";
  204. pluginString += " lv2:name \"Audio Output " + d_string(i+1) + "\" ;\n";
  205. if (i+1 == DISTRHO_PLUGIN_NUM_OUTPUTS)
  206. pluginString += " ] ;\n\n";
  207. else
  208. pluginString += " ] ,\n";
  209. }
  210. pluginString += "\n";
  211. #endif
  212. #if DISTRHO_LV2_USE_EVENTS_IN
  213. pluginString += " lv2:port [\n";
  214. pluginString += " a lv2:InputPort, atom:AtomPort ;\n";
  215. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  216. pluginString += " lv2:name \"Events Input\" ;\n";
  217. pluginString += " lv2:symbol \"lv2_events_in\" ;\n";
  218. pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n";
  219. pluginString += " atom:bufferType atom:Sequence ;\n";
  220. # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
  221. pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
  222. # endif
  223. # if DISTRHO_PLUGIN_HAS_MIDI_INPUT
  224. pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
  225. # endif
  226. # if DISTRHO_PLUGIN_WANT_TIMEPOS
  227. pluginString += " atom:supports <" LV2_TIME__Position "> ;\n";
  228. # endif
  229. pluginString += " ] ;\n\n";
  230. ++portIndex;
  231. #endif
  232. #if DISTRHO_LV2_USE_EVENTS_OUT
  233. pluginString += " lv2:port [\n";
  234. pluginString += " a lv2:OutputPort, atom:AtomPort ;\n";
  235. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  236. pluginString += " lv2:name \"Events Output\" ;\n";
  237. pluginString += " lv2:symbol \"lv2_events_out\" ;\n";
  238. pluginString += " rsz:minimumSize " + d_string(DISTRHO_PLUGIN_MINIMUM_BUFFER_SIZE) + " ;\n";
  239. pluginString += " atom:bufferType atom:Sequence ;\n";
  240. # if (DISTRHO_PLUGIN_WANT_STATE && DISTRHO_PLUGIN_HAS_UI)
  241. pluginString += " atom:supports <" LV2_ATOM__String "> ;\n";
  242. # endif
  243. # if DISTRHO_PLUGIN_HAS_MIDI_OUTPUT
  244. pluginString += " atom:supports <" LV2_MIDI__MidiEvent "> ;\n";
  245. # endif
  246. pluginString += " ] ;\n\n";
  247. ++portIndex;
  248. #endif
  249. #if DISTRHO_PLUGIN_WANT_LATENCY
  250. pluginString += " lv2:port [\n";
  251. pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
  252. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  253. pluginString += " lv2:name \"Latency\" ;\n";
  254. pluginString += " lv2:symbol \"lv2_latency\" ;\n";
  255. pluginString += " lv2:designation lv2:latency ;\n";
  256. pluginString += " lv2:portProperty lv2:reportsLatency, lv2:integer ;\n";
  257. pluginString += " ] ;\n\n";
  258. ++portIndex;
  259. #endif
  260. for (uint32_t i=0, count=plugin.getParameterCount(); i < count; ++i, ++portIndex)
  261. {
  262. if (i == 0)
  263. pluginString += " lv2:port [\n";
  264. else
  265. pluginString += " [\n";
  266. if (plugin.isParameterOutput(i))
  267. pluginString += " a lv2:OutputPort, lv2:ControlPort ;\n";
  268. else
  269. pluginString += " a lv2:InputPort, lv2:ControlPort ;\n";
  270. pluginString += " lv2:index " + d_string(portIndex) + " ;\n";
  271. pluginString += " lv2:name \"" + plugin.getParameterName(i) + "\" ;\n";
  272. // symbol
  273. {
  274. d_string symbol(plugin.getParameterSymbol(i));
  275. if (symbol.isEmpty())
  276. symbol = "lv2_port_" + d_string(portIndex-1);
  277. pluginString += " lv2:symbol \"" + symbol + "\" ;\n";
  278. }
  279. // ranges
  280. {
  281. const ParameterRanges& ranges(plugin.getParameterRanges(i));
  282. if (plugin.getParameterHints(i) & kParameterIsInteger)
  283. {
  284. pluginString += " lv2:default " + d_string(int(plugin.getParameterValue(i))) + " ;\n";
  285. pluginString += " lv2:minimum " + d_string(int(ranges.min)) + " ;\n";
  286. pluginString += " lv2:maximum " + d_string(int(ranges.max)) + " ;\n";
  287. }
  288. else
  289. {
  290. pluginString += " lv2:default " + d_string(plugin.getParameterValue(i)) + " ;\n";
  291. pluginString += " lv2:minimum " + d_string(ranges.min) + " ;\n";
  292. pluginString += " lv2:maximum " + d_string(ranges.max) + " ;\n";
  293. }
  294. }
  295. // unit
  296. {
  297. const d_string& unit(plugin.getParameterUnit(i));
  298. if (! unit.isEmpty())
  299. {
  300. if (unit == "db" || unit == "dB")
  301. {
  302. pluginString += " unit:unit unit:db ;\n";
  303. }
  304. else if (unit == "hz" || unit == "Hz")
  305. {
  306. pluginString += " unit:unit unit:hz ;\n";
  307. }
  308. else if (unit == "khz" || unit == "kHz")
  309. {
  310. pluginString += " unit:unit unit:khz ;\n";
  311. }
  312. else if (unit == "mhz" || unit == "mHz")
  313. {
  314. pluginString += " unit:unit unit:mhz ;\n";
  315. }
  316. else if (unit == "%")
  317. {
  318. pluginString += " unit:unit unit:pc ;\n";
  319. }
  320. else
  321. {
  322. pluginString += " unit:unit [\n";
  323. pluginString += " a unit:Unit ;\n";
  324. pluginString += " unit:name \"" + unit + "\" ;\n";
  325. pluginString += " unit:symbol \"" + unit + "\" ;\n";
  326. pluginString += " unit:render \"%f " + unit + "\" ;\n";
  327. pluginString += " ] ;\n";
  328. }
  329. }
  330. }
  331. // hints
  332. {
  333. const uint32_t hints(plugin.getParameterHints(i));
  334. if (hints & kParameterIsBoolean)
  335. pluginString += " lv2:portProperty lv2:toggled ;\n";
  336. if (hints & kParameterIsInteger)
  337. pluginString += " lv2:portProperty lv2:integer ;\n";
  338. if (hints & kParameterIsLogarithmic)
  339. pluginString += " lv2:portProperty <" LV2_PORT_PROPS__logarithmic "> ;\n";
  340. if ((hints & kParameterIsAutomable) == 0 && ! plugin.isParameterOutput(i))
  341. {
  342. pluginString += " lv2:portProperty <" LV2_PORT_PROPS__expensive "> ,\n";
  343. pluginString += " <" LV2_KXSTUDIO_PROPERTIES__NonAutomable "> ;\n";
  344. }
  345. }
  346. if (i+1 == count)
  347. pluginString += " ] ;\n\n";
  348. else
  349. pluginString += " ] ,\n";
  350. }
  351. }
  352. pluginString += " doap:name \"" + d_string(plugin.getName()) + "\" ;\n";
  353. pluginString += " doap:maintainer [ foaf:name \"" + d_string(plugin.getMaker()) + "\" ] .\n";
  354. pluginFile << pluginString << std::endl;
  355. pluginFile.close();
  356. std::cout << " done!" << std::endl;
  357. }
  358. }