Audio plugin host https://kx.studio/carla
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.

335 lines
14KB

  1. /*
  2. * Carla CachedPlugins Test
  3. * Copyright (C) 2015 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaUtils.h"
  18. #include "CarlaLv2Utils.hpp"
  19. #include "CarlaString.hpp"
  20. namespace CB = CarlaBackend;
  21. static const char* const gNullCharPtr = "";
  22. // -------------------------------------------------------------------------------------------------------------------
  23. _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept
  24. : category(CB::PLUGIN_CATEGORY_NONE),
  25. hints(0x0),
  26. audioIns(0),
  27. audioOuts(0),
  28. midiIns(0),
  29. midiOuts(0),
  30. parameterIns(0),
  31. parameterOuts(0),
  32. name(gNullCharPtr),
  33. label(gNullCharPtr),
  34. maker(gNullCharPtr),
  35. copyright(gNullCharPtr) {}
  36. // -------------------------------------------------------------------------------------------------------------------
  37. int main()
  38. {
  39. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  40. lv2World.initIfNeeded("~/.lv2/");
  41. const uint pcount = lv2World.getPluginCount();
  42. CARLA_SAFE_ASSERT_RETURN(pcount > 0, 1);
  43. CarlaCachedPluginInfo info;
  44. for (uint index=0; index<pcount; ++index)
  45. {
  46. const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index));
  47. CARLA_SAFE_ASSERT_BREAK(cPlugin != nullptr);
  48. Lilv::Plugin lilvPlugin(cPlugin);
  49. CARLA_SAFE_ASSERT_BREAK(lilvPlugin.get_uri().is_uri());
  50. carla_stdout("Filling info for LV2 with URI '%s'", lilvPlugin.get_uri().as_uri());
  51. // features
  52. info.hints = 0x0;
  53. if (lilvPlugin.get_uis().size() > 0 || lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr)
  54. info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
  55. {
  56. Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features());
  57. LILV_FOREACH(nodes, it, lilvFeatureNodes)
  58. {
  59. Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it));
  60. const char* const featureURI(lilvFeatureNode.as_uri());
  61. CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
  62. if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0)
  63. info.hints |= CB::PLUGIN_IS_RTSAFE;
  64. }
  65. lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodes.me));
  66. }
  67. // category
  68. info.category = CB::PLUGIN_CATEGORY_NONE;
  69. {
  70. Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type));
  71. if (typeNodes.size() > 0)
  72. {
  73. if (typeNodes.contains(lv2World.class_allpass))
  74. info.category = CB::PLUGIN_CATEGORY_FILTER;
  75. if (typeNodes.contains(lv2World.class_amplifier))
  76. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  77. if (typeNodes.contains(lv2World.class_analyzer))
  78. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  79. if (typeNodes.contains(lv2World.class_bandpass))
  80. info.category = CB::PLUGIN_CATEGORY_FILTER;
  81. if (typeNodes.contains(lv2World.class_chorus))
  82. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  83. if (typeNodes.contains(lv2World.class_comb))
  84. info.category = CB::PLUGIN_CATEGORY_FILTER;
  85. if (typeNodes.contains(lv2World.class_compressor))
  86. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  87. if (typeNodes.contains(lv2World.class_constant))
  88. info.category = CB::PLUGIN_CATEGORY_OTHER;
  89. if (typeNodes.contains(lv2World.class_converter))
  90. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  91. if (typeNodes.contains(lv2World.class_delay))
  92. info.category = CB::PLUGIN_CATEGORY_DELAY;
  93. if (typeNodes.contains(lv2World.class_distortion))
  94. info.category = CB::PLUGIN_CATEGORY_DISTORTION;
  95. if (typeNodes.contains(lv2World.class_dynamics))
  96. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  97. if (typeNodes.contains(lv2World.class_eq))
  98. info.category = CB::PLUGIN_CATEGORY_EQ;
  99. if (typeNodes.contains(lv2World.class_envelope))
  100. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  101. if (typeNodes.contains(lv2World.class_expander))
  102. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  103. if (typeNodes.contains(lv2World.class_filter))
  104. info.category = CB::PLUGIN_CATEGORY_FILTER;
  105. if (typeNodes.contains(lv2World.class_flanger))
  106. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  107. if (typeNodes.contains(lv2World.class_function))
  108. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  109. if (typeNodes.contains(lv2World.class_gate))
  110. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  111. if (typeNodes.contains(lv2World.class_generator))
  112. info.category = CB::PLUGIN_CATEGORY_OTHER;
  113. if (typeNodes.contains(lv2World.class_highpass))
  114. info.category = CB::PLUGIN_CATEGORY_FILTER;
  115. if (typeNodes.contains(lv2World.class_limiter))
  116. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  117. if (typeNodes.contains(lv2World.class_lowpass))
  118. info.category = CB::PLUGIN_CATEGORY_FILTER;
  119. if (typeNodes.contains(lv2World.class_mixer))
  120. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  121. if (typeNodes.contains(lv2World.class_modulator))
  122. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  123. if (typeNodes.contains(lv2World.class_multiEQ))
  124. info.category = CB::PLUGIN_CATEGORY_EQ;
  125. if (typeNodes.contains(lv2World.class_oscillator))
  126. info.category = CB::PLUGIN_CATEGORY_OTHER;
  127. if (typeNodes.contains(lv2World.class_paraEQ))
  128. info.category = CB::PLUGIN_CATEGORY_EQ;
  129. if (typeNodes.contains(lv2World.class_phaser))
  130. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  131. if (typeNodes.contains(lv2World.class_pitch))
  132. info.category = CB::PLUGIN_CATEGORY_OTHER;
  133. if (typeNodes.contains(lv2World.class_reverb))
  134. info.category = CB::PLUGIN_CATEGORY_DELAY;
  135. if (typeNodes.contains(lv2World.class_simulator))
  136. info.category = CB::PLUGIN_CATEGORY_OTHER;
  137. if (typeNodes.contains(lv2World.class_spatial))
  138. info.category = CB::PLUGIN_CATEGORY_OTHER;
  139. if (typeNodes.contains(lv2World.class_spectral))
  140. info.category = CB::PLUGIN_CATEGORY_OTHER;
  141. if (typeNodes.contains(lv2World.class_utility))
  142. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  143. if (typeNodes.contains(lv2World.class_waveshaper))
  144. info.category = CB::PLUGIN_CATEGORY_DISTORTION;
  145. if (typeNodes.contains(lv2World.class_instrument))
  146. {
  147. info.category = CB::PLUGIN_CATEGORY_SYNTH;
  148. info.hints |= CB::PLUGIN_IS_SYNTH;
  149. }
  150. }
  151. lilv_nodes_free(const_cast<LilvNodes*>(typeNodes.me));
  152. }
  153. // number data
  154. info.audioIns = 0;
  155. info.audioOuts = 0;
  156. info.midiIns = 0;
  157. info.midiOuts = 0;
  158. info.parameterIns = 0;
  159. info.parameterOuts = 0;
  160. for (uint i=0, count=lilvPlugin.get_num_ports(); i<count; ++i)
  161. {
  162. Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i));
  163. bool isInput;
  164. /**/ if (lilvPort.is_a(lv2World.port_input))
  165. isInput = true;
  166. else if (lilvPort.is_a(lv2World.port_output))
  167. isInput = false;
  168. else
  169. continue;
  170. /**/ if (lilvPort.is_a(lv2World.port_control))
  171. {
  172. // skip some control ports
  173. if (lilvPort.has_property(lv2World.reportsLatency))
  174. continue;
  175. if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me))
  176. {
  177. bool skip = false;
  178. if (const char* const designation = lilv_node_as_string(designationNode))
  179. {
  180. /**/ if (std::strcmp(designation, LV2_CORE__control) == 0)
  181. skip = true;
  182. else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0)
  183. skip = true;
  184. else if (std::strcmp(designation, LV2_CORE__latency) == 0)
  185. skip = true;
  186. else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0)
  187. skip = true;
  188. else if (std::strcmp(designation, LV2_TIME__bar) == 0)
  189. skip = true;
  190. else if (std::strcmp(designation, LV2_TIME__barBeat) == 0)
  191. skip = true;
  192. else if (std::strcmp(designation, LV2_TIME__beat) == 0)
  193. skip = true;
  194. else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0)
  195. skip = true;
  196. else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0)
  197. skip = true;
  198. else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0)
  199. skip = true;
  200. else if (std::strcmp(designation, LV2_TIME__frame) == 0)
  201. skip = true;
  202. else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0)
  203. skip = true;
  204. else if (std::strcmp(designation, LV2_TIME__speed) == 0)
  205. skip = true;
  206. else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
  207. skip = true;
  208. }
  209. lilv_node_free(designationNode);
  210. if (skip)
  211. continue;
  212. }
  213. if (isInput)
  214. ++(info.parameterIns);
  215. else
  216. ++(info.parameterOuts);
  217. }
  218. else if (lilvPort.is_a(lv2World.port_audio))
  219. {
  220. if (isInput)
  221. ++(info.audioIns);
  222. else
  223. ++(info.audioOuts);
  224. }
  225. else if (lilvPort.is_a(lv2World.port_cv))
  226. {
  227. }
  228. else if (lilvPort.is_a(lv2World.port_atom))
  229. {
  230. Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports));
  231. for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it))
  232. {
  233. const Lilv::Node node(lilv_nodes_get(supportNodes.me, it));
  234. CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
  235. if (node.equals(lv2World.midi_event))
  236. {
  237. if (isInput)
  238. ++(info.midiIns);
  239. else
  240. ++(info.midiOuts);
  241. }
  242. }
  243. lilv_nodes_free(const_cast<LilvNodes*>(supportNodes.me));
  244. }
  245. else if (lilvPort.is_a(lv2World.port_event))
  246. {
  247. if (lilvPort.supports_event(lv2World.midi_event))
  248. {
  249. if (isInput)
  250. ++(info.midiIns);
  251. else
  252. ++(info.midiOuts);
  253. }
  254. }
  255. else if (lilvPort.is_a(lv2World.port_midi))
  256. {
  257. if (isInput)
  258. ++(info.midiIns);
  259. else
  260. ++(info.midiOuts);
  261. }
  262. }
  263. // text data
  264. static CarlaString suri, sname, smaker, slicense;
  265. suri.clear(); sname.clear(); smaker.clear(); slicense.clear();
  266. suri = lilvPlugin.get_uri().as_uri();
  267. if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me))
  268. {
  269. if (const char* const name = lilv_node_as_string(nameNode))
  270. sname = name;
  271. lilv_node_free(nameNode);
  272. }
  273. if (const char* const author = lilvPlugin.get_author_name().as_string())
  274. smaker = author;
  275. Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license));
  276. if (licenseNodes.size() > 0)
  277. {
  278. if (const char* const license = licenseNodes.get_first().as_string())
  279. slicense = license;
  280. }
  281. lilv_nodes_free(const_cast<LilvNodes*>(licenseNodes.me));
  282. info.name = sname;
  283. info.label = suri;
  284. info.maker = smaker;
  285. info.copyright = slicense;
  286. }
  287. return 0;
  288. }
  289. // #include "CarlaUtils.cpp"