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.

665 lines
22KB

  1. /*
  2. * Carla Plugin Host
  3. * Copyright (C) 2011-2014 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 "CarlaHost.h"
  18. #include "CarlaNative.h"
  19. #include "CarlaLv2Utils.hpp"
  20. #include "CarlaPlugin.hpp"
  21. #include "CarlaString.hpp"
  22. #include "juce_audio_formats.h"
  23. namespace CB = CarlaBackend;
  24. // -------------------------------------------------------------------------------------------------------------------
  25. // Always return a valid string ptr
  26. static const char* const gNullCharPtr = "";
  27. static void checkStringPtr(const char*& charPtr) noexcept
  28. {
  29. if (charPtr == nullptr)
  30. charPtr = gNullCharPtr;
  31. }
  32. // -------------------------------------------------------------------------------------------------------------------
  33. // Constructors
  34. _CarlaPluginInfo::_CarlaPluginInfo() noexcept
  35. : type(CB::PLUGIN_NONE),
  36. category(CB::PLUGIN_CATEGORY_NONE),
  37. hints(0x0),
  38. optionsAvailable(0x0),
  39. optionsEnabled(0x0),
  40. filename(gNullCharPtr),
  41. name(gNullCharPtr),
  42. label(gNullCharPtr),
  43. maker(gNullCharPtr),
  44. copyright(gNullCharPtr),
  45. iconName(gNullCharPtr),
  46. uniqueId(0) {}
  47. _CarlaPluginInfo::~_CarlaPluginInfo() noexcept
  48. {
  49. if (label != gNullCharPtr)
  50. delete[] label;
  51. if (maker != gNullCharPtr)
  52. delete[] maker;
  53. if (copyright != gNullCharPtr)
  54. delete[] copyright;
  55. }
  56. _CarlaCachedPluginInfo::_CarlaCachedPluginInfo() noexcept
  57. : category(CB::PLUGIN_CATEGORY_NONE),
  58. hints(0x0),
  59. audioIns(0),
  60. audioOuts(0),
  61. midiIns(0),
  62. midiOuts(0),
  63. parameterIns(0),
  64. parameterOuts(0),
  65. name(gNullCharPtr),
  66. label(gNullCharPtr),
  67. maker(gNullCharPtr),
  68. copyright(gNullCharPtr) {}
  69. _CarlaParameterInfo::_CarlaParameterInfo() noexcept
  70. : name(gNullCharPtr),
  71. symbol(gNullCharPtr),
  72. unit(gNullCharPtr),
  73. scalePointCount(0) {}
  74. _CarlaParameterInfo::~_CarlaParameterInfo() noexcept
  75. {
  76. if (name != gNullCharPtr)
  77. delete[] name;
  78. if (symbol != gNullCharPtr)
  79. delete[] symbol;
  80. if (unit != gNullCharPtr)
  81. delete[] unit;
  82. }
  83. _CarlaScalePointInfo::_CarlaScalePointInfo() noexcept
  84. : value(0.0f),
  85. label(gNullCharPtr) {}
  86. _CarlaScalePointInfo::~_CarlaScalePointInfo() noexcept
  87. {
  88. if (label != gNullCharPtr)
  89. delete[] label;
  90. }
  91. _CarlaTransportInfo::_CarlaTransportInfo() noexcept
  92. : playing(false),
  93. frame(0),
  94. bar(0),
  95. beat(0),
  96. tick(0),
  97. bpm(0.0) {}
  98. // -------------------------------------------------------------------------------------------------------------------
  99. const char* carla_get_complete_license_text()
  100. {
  101. carla_debug("carla_get_complete_license_text()");
  102. static CarlaString retText;
  103. if (retText.isEmpty())
  104. {
  105. retText =
  106. "<p>This current Carla build is using the following features and 3rd-party code:</p>"
  107. "<ul>"
  108. // Plugin formats
  109. "<li>LADSPA plugin support</li>"
  110. "<li>DSSI plugin support</li>"
  111. "<li>LV2 plugin support</li>"
  112. #ifdef VESTIGE_HEADER
  113. "<li>VST plugin support using VeSTige header by Javier Serrano Polo</li>"
  114. #else
  115. "<li>VST plugin support using official VST SDK 2.4 [1]</li>"
  116. #endif
  117. #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN)
  118. "<li>VST3 plugin support using official VST SDK 3.6 [1]</li>"
  119. #endif
  120. #ifdef CARLA_OS_MAC
  121. "<li>AU plugin support</li>"
  122. #endif
  123. // Sample kit libraries
  124. #ifdef HAVE_FLUIDSYNTH
  125. "<li>FluidSynth library for SF2 support</li>"
  126. #endif
  127. #ifdef HAVE_LINUXSAMPLER
  128. "<li>LinuxSampler library for GIG and SFZ support [2]</li>"
  129. #endif
  130. // Internal plugins
  131. "<li>NekoFilter plugin code based on lv2fil by Nedko Arnaudov and Fons Adriaensen</li>"
  132. #ifdef WANT_ZYNADDSUBFX
  133. "<li>ZynAddSubFX plugin code</li>"
  134. #endif
  135. // misc libs
  136. "<li>base64 utilities based on code by Ren\u00E9 Nyffenegger</li>"
  137. #ifdef CARLA_OS_MAC
  138. "<li>sem_timedwait for Mac OS by Keith Shortridge</li>"
  139. #endif
  140. "<li>liblo library for OSC support</li>"
  141. "<li>rtmempool library by Nedko Arnaudov"
  142. "<li>serd, sord, sratom and lilv libraries for LV2 discovery</li>"
  143. #if ! (defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN))
  144. "<li>RtAudio and RtMidi libraries for extra Audio and MIDI support</li>"
  145. #endif
  146. // end
  147. "</ul>"
  148. "<p>"
  149. #if defined(CARLA_OS_MAC) || defined(CARLA_OS_WIN) || ! defined(VESTIGE_HEADER)
  150. // Required by VST SDK
  151. "&nbsp;[1] Trademark of Steinberg Media Technologies GmbH.<br/>"
  152. #endif
  153. #ifdef HAVE_LINUXSAMPLER
  154. // LinuxSampler GPL exception
  155. "&nbsp;[2] Using LinuxSampler code in commercial hardware or software products is not allowed without prior written authorization by the authors."
  156. #endif
  157. "</p>"
  158. ;
  159. }
  160. return retText;
  161. }
  162. const char* carla_get_juce_version()
  163. {
  164. carla_debug("carla_get_juce_version()");
  165. static CarlaString retVersion;
  166. if (retVersion.isEmpty())
  167. {
  168. if (const char* const version = juce::SystemStats::getJUCEVersion().toRawUTF8())
  169. retVersion = version+6;
  170. else
  171. retVersion = "3.0";
  172. }
  173. return retVersion;
  174. }
  175. const char* carla_get_supported_file_extensions()
  176. {
  177. carla_debug("carla_get_supported_file_extensions()");
  178. static CarlaString retText;
  179. if (retText.isEmpty())
  180. {
  181. retText =
  182. // Base types
  183. "*.carxp;*.carxs"
  184. // MIDI files
  185. ";*.mid;*.midi"
  186. #ifdef HAVE_FLUIDSYNTH
  187. // fluidsynth (sf2)
  188. ";*.sf2"
  189. #endif
  190. #ifdef HAVE_LINUXSAMPLER
  191. // linuxsampler (gig and sfz)
  192. ";*.gig;*.sfz"
  193. #endif
  194. #ifdef WANT_ZYNADDSUBFX
  195. // zynaddsubfx presets
  196. ";*.xmz;*.xiz"
  197. #endif
  198. ;
  199. #ifndef BUILD_BRIDGE
  200. // Audio files
  201. {
  202. using namespace juce;
  203. AudioFormatManager afm;
  204. afm.registerBasicFormats();
  205. String juceFormats;
  206. for (AudioFormat **it=afm.begin(), **end=afm.end(); it != end; ++it)
  207. {
  208. const StringArray& exts((*it)->getFileExtensions());
  209. for (String *eit=exts.begin(), *eend=exts.end(); eit != eend; ++eit)
  210. juceFormats += String(";*" + (*eit)).toRawUTF8();
  211. }
  212. retText += juceFormats.toRawUTF8();
  213. }
  214. #endif
  215. }
  216. return retText;
  217. }
  218. // -------------------------------------------------------------------------------------------------------------------
  219. uint carla_get_cached_plugin_count(PluginType ptype, const char* pluginPath)
  220. {
  221. CARLA_SAFE_ASSERT_RETURN(ptype == CB::PLUGIN_INTERNAL || ptype == CB::PLUGIN_LV2 || ptype == CB::PLUGIN_AU, 0);
  222. carla_debug("carla_get_cached_plugin_count(%i:%s)", ptype, CB::PluginType2Str(ptype));
  223. switch (ptype)
  224. {
  225. case CB::PLUGIN_INTERNAL: {
  226. #ifndef BUILD_BRIDGE
  227. return static_cast<uint>(CarlaPlugin::getNativePluginCount());
  228. #else
  229. return 0;
  230. #endif
  231. }
  232. case CB::PLUGIN_LV2: {
  233. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  234. lv2World.initIfNeeded(pluginPath);
  235. return lv2World.getPluginCount();
  236. }
  237. case CB::PLUGIN_AU: {
  238. // TODO
  239. return 0;
  240. }
  241. default:
  242. return 0;
  243. }
  244. }
  245. const CarlaCachedPluginInfo* carla_get_cached_plugin_info(PluginType ptype, uint index)
  246. {
  247. CARLA_SAFE_ASSERT_RETURN(ptype == CB::PLUGIN_INTERNAL || ptype == CB::PLUGIN_LV2 || ptype == CB::PLUGIN_AU, nullptr);
  248. carla_debug("carla_get_cached_plugin_info(%i:%s, %i)", ptype, CB::PluginType2Str(ptype), index);
  249. static CarlaCachedPluginInfo info;
  250. switch (ptype)
  251. {
  252. case CB::PLUGIN_INTERNAL: {
  253. #ifndef BUILD_BRIDGE
  254. const NativePluginDescriptor* const desc(CarlaPlugin::getNativePluginDescriptor(index));
  255. CARLA_SAFE_ASSERT_RETURN(desc != nullptr, nullptr);
  256. info.category = static_cast<CB::PluginCategory>(desc->category);
  257. info.hints = 0x0;
  258. if (desc->hints & ::PLUGIN_IS_RTSAFE)
  259. info.hints |= CB::PLUGIN_IS_RTSAFE;
  260. if (desc->hints & ::PLUGIN_IS_SYNTH)
  261. info.hints |= CB::PLUGIN_IS_SYNTH;
  262. if (desc->hints & ::PLUGIN_HAS_UI)
  263. info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
  264. if (desc->hints & ::PLUGIN_NEEDS_FIXED_BUFFERS)
  265. info.hints |= CB::PLUGIN_NEEDS_FIXED_BUFFERS;
  266. if (desc->hints & ::PLUGIN_NEEDS_SINGLE_THREAD)
  267. info.hints |= CB::PLUGIN_NEEDS_SINGLE_THREAD;
  268. info.audioIns = desc->audioIns;
  269. info.audioOuts = desc->audioOuts;
  270. info.midiIns = desc->midiIns;
  271. info.midiOuts = desc->midiOuts;
  272. info.parameterIns = desc->paramIns;
  273. info.parameterOuts = desc->paramOuts;
  274. info.name = desc->name;
  275. info.label = desc->label;
  276. info.maker = desc->maker;
  277. info.copyright = desc->copyright;
  278. #else
  279. return nullptr;
  280. #endif
  281. }
  282. case CB::PLUGIN_LV2: {
  283. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  284. const LilvPlugin* const cPlugin(lv2World.getPluginFromIndex(index));
  285. CARLA_SAFE_ASSERT_RETURN(cPlugin != nullptr, nullptr);
  286. Lilv::Plugin lilvPlugin(cPlugin);
  287. CARLA_SAFE_ASSERT_RETURN(lilvPlugin.get_uri().is_uri(), nullptr);
  288. // features
  289. info.hints = 0x0;
  290. if (lilvPlugin.get_uis().size() > 0)
  291. info.hints |= CB::PLUGIN_HAS_CUSTOM_UI;
  292. {
  293. Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features());
  294. LILV_FOREACH(nodes, it, lilvFeatureNodes)
  295. {
  296. Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it));
  297. const char* const featureURI(lilvFeatureNode.as_uri());
  298. CARLA_SAFE_ASSERT_CONTINUE(featureURI != nullptr);
  299. if (std::strcmp(featureURI, LV2_CORE__hardRTCapable) == 0)
  300. info.hints |= CB::PLUGIN_IS_RTSAFE;
  301. }
  302. lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodes.me));
  303. }
  304. // category
  305. info.category = CB::PLUGIN_CATEGORY_NONE;
  306. {
  307. Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type));
  308. if (typeNodes.size() > 0)
  309. {
  310. if (typeNodes.contains(lv2World.class_allpass))
  311. info.category = CB::PLUGIN_CATEGORY_FILTER;
  312. if (typeNodes.contains(lv2World.class_amplifier))
  313. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  314. if (typeNodes.contains(lv2World.class_analyzer))
  315. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  316. if (typeNodes.contains(lv2World.class_bandpass))
  317. info.category = CB::PLUGIN_CATEGORY_FILTER;
  318. if (typeNodes.contains(lv2World.class_chorus))
  319. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  320. if (typeNodes.contains(lv2World.class_comb))
  321. info.category = CB::PLUGIN_CATEGORY_FILTER;
  322. if (typeNodes.contains(lv2World.class_compressor))
  323. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  324. if (typeNodes.contains(lv2World.class_constant))
  325. info.category = CB::PLUGIN_CATEGORY_OTHER;
  326. if (typeNodes.contains(lv2World.class_converter))
  327. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  328. if (typeNodes.contains(lv2World.class_delay))
  329. info.category = CB::PLUGIN_CATEGORY_DELAY;
  330. if (typeNodes.contains(lv2World.class_distortion))
  331. info.category = CB::PLUGIN_CATEGORY_DISTORTION;
  332. if (typeNodes.contains(lv2World.class_dynamics))
  333. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  334. if (typeNodes.contains(lv2World.class_eq))
  335. info.category = CB::PLUGIN_CATEGORY_EQ;
  336. if (typeNodes.contains(lv2World.class_envelope))
  337. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  338. if (typeNodes.contains(lv2World.class_expander))
  339. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  340. if (typeNodes.contains(lv2World.class_filter))
  341. info.category = CB::PLUGIN_CATEGORY_FILTER;
  342. if (typeNodes.contains(lv2World.class_flanger))
  343. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  344. if (typeNodes.contains(lv2World.class_function))
  345. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  346. if (typeNodes.contains(lv2World.class_gate))
  347. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  348. if (typeNodes.contains(lv2World.class_generator))
  349. info.category = CB::PLUGIN_CATEGORY_OTHER;
  350. if (typeNodes.contains(lv2World.class_highpass))
  351. info.category = CB::PLUGIN_CATEGORY_FILTER;
  352. if (typeNodes.contains(lv2World.class_limiter))
  353. info.category = CB::PLUGIN_CATEGORY_DYNAMICS;
  354. if (typeNodes.contains(lv2World.class_lowpass))
  355. info.category = CB::PLUGIN_CATEGORY_FILTER;
  356. if (typeNodes.contains(lv2World.class_mixer))
  357. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  358. if (typeNodes.contains(lv2World.class_modulator))
  359. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  360. if (typeNodes.contains(lv2World.class_multiEQ))
  361. info.category = CB::PLUGIN_CATEGORY_EQ;
  362. if (typeNodes.contains(lv2World.class_oscillator))
  363. info.category = CB::PLUGIN_CATEGORY_OTHER;
  364. if (typeNodes.contains(lv2World.class_paraEQ))
  365. info.category = CB::PLUGIN_CATEGORY_EQ;
  366. if (typeNodes.contains(lv2World.class_phaser))
  367. info.category = CB::PLUGIN_CATEGORY_MODULATOR;
  368. if (typeNodes.contains(lv2World.class_pitch))
  369. info.category = CB::PLUGIN_CATEGORY_OTHER;
  370. if (typeNodes.contains(lv2World.class_reverb))
  371. info.category = CB::PLUGIN_CATEGORY_DELAY;
  372. if (typeNodes.contains(lv2World.class_simulator))
  373. info.category = CB::PLUGIN_CATEGORY_OTHER;
  374. if (typeNodes.contains(lv2World.class_spatial))
  375. info.category = CB::PLUGIN_CATEGORY_OTHER;
  376. if (typeNodes.contains(lv2World.class_spectral))
  377. info.category = CB::PLUGIN_CATEGORY_OTHER;
  378. if (typeNodes.contains(lv2World.class_utility))
  379. info.category = CB::PLUGIN_CATEGORY_UTILITY;
  380. if (typeNodes.contains(lv2World.class_waveshaper))
  381. info.category = CB::PLUGIN_CATEGORY_DISTORTION;
  382. if (typeNodes.contains(lv2World.class_instrument))
  383. {
  384. info.category = CB::PLUGIN_CATEGORY_SYNTH;
  385. info.hints |= PLUGIN_IS_SYNTH;
  386. }
  387. }
  388. lilv_nodes_free(const_cast<LilvNodes*>(typeNodes.me));
  389. }
  390. // number data
  391. info.audioIns = 0;
  392. info.audioOuts = 0;
  393. info.midiIns = 0;
  394. info.midiOuts = 0;
  395. info.parameterIns = 0;
  396. info.parameterOuts = 0;
  397. for (uint i=0, count=lilvPlugin.get_num_ports(); i<count; ++i)
  398. {
  399. Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i));
  400. bool isInput;
  401. /**/ if (lilvPort.is_a(lv2World.port_input))
  402. isInput = true;
  403. else if (lilvPort.is_a(lv2World.port_output))
  404. isInput = false;
  405. else
  406. continue;
  407. /**/ if (lilvPort.is_a(lv2World.port_control))
  408. {
  409. // skip some control ports
  410. if (lilvPort.has_property(lv2World.reportsLatency))
  411. continue;
  412. if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me))
  413. {
  414. bool skip = false;
  415. if (const char* const designation = lilv_node_as_string(designationNode))
  416. {
  417. /**/ if (std::strcmp(designation, LV2_CORE__control) == 0)
  418. skip = true;
  419. else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0)
  420. skip = true;
  421. else if (std::strcmp(designation, LV2_CORE__latency) == 0)
  422. skip = true;
  423. else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0)
  424. skip = true;
  425. else if (std::strcmp(designation, LV2_TIME__bar) == 0)
  426. skip = true;
  427. else if (std::strcmp(designation, LV2_TIME__barBeat) == 0)
  428. skip = true;
  429. else if (std::strcmp(designation, LV2_TIME__beat) == 0)
  430. skip = true;
  431. else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0)
  432. skip = true;
  433. else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0)
  434. skip = true;
  435. else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0)
  436. skip = true;
  437. else if (std::strcmp(designation, LV2_TIME__frame) == 0)
  438. skip = true;
  439. else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0)
  440. skip = true;
  441. else if (std::strcmp(designation, LV2_TIME__speed) == 0)
  442. skip = true;
  443. else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
  444. skip = true;
  445. }
  446. lilv_node_free(designationNode);
  447. if (skip)
  448. continue;
  449. }
  450. if (isInput)
  451. ++(info.parameterIns);
  452. else
  453. ++(info.parameterOuts);
  454. }
  455. else if (lilvPort.is_a(lv2World.port_audio))
  456. {
  457. if (isInput)
  458. ++(info.audioIns);
  459. else
  460. ++(info.audioOuts);
  461. }
  462. else if (lilvPort.is_a(lv2World.port_cv))
  463. {
  464. }
  465. else if (lilvPort.is_a(lv2World.port_atom))
  466. {
  467. Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports));
  468. for (LilvIter *it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it))
  469. {
  470. const Lilv::Node node(lilv_nodes_get(supportNodes.me, it));
  471. CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
  472. if (node.equals(lv2World.midi_event))
  473. {
  474. if (isInput)
  475. ++(info.midiIns);
  476. else
  477. ++(info.midiOuts);
  478. }
  479. }
  480. lilv_nodes_free(const_cast<LilvNodes*>(supportNodes.me));
  481. }
  482. else if (lilvPort.is_a(lv2World.port_event))
  483. {
  484. if (lilvPort.supports_event(lv2World.midi_event))
  485. {
  486. if (isInput)
  487. ++(info.midiIns);
  488. else
  489. ++(info.midiOuts);
  490. }
  491. }
  492. else if (lilvPort.is_a(lv2World.port_midi))
  493. {
  494. if (isInput)
  495. ++(info.midiIns);
  496. else
  497. ++(info.midiOuts);
  498. }
  499. }
  500. // text data
  501. static CarlaString suri, sname, smaker, slicense;
  502. suri.clear(); sname.clear(); smaker.clear(); slicense.clear();
  503. suri = lilvPlugin.get_uri().as_uri();
  504. if (const char* const name = lilvPlugin.get_name().as_string())
  505. sname = name;
  506. else
  507. sname.clear();
  508. if (const char* const author = lilvPlugin.get_author_name().as_string())
  509. smaker = author;
  510. else
  511. smaker.clear();
  512. Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license));
  513. if (licenseNodes.size() > 0)
  514. {
  515. if (const char* const license = licenseNodes.get_first().as_string())
  516. slicense = license;
  517. }
  518. lilv_nodes_free(const_cast<LilvNodes*>(licenseNodes.me));
  519. info.name = sname;
  520. info.label = suri;
  521. info.maker = smaker;
  522. info.copyright = slicense;
  523. return &info;
  524. }
  525. case CB::PLUGIN_AU: {
  526. // TODO
  527. return nullptr;
  528. }
  529. default:
  530. return nullptr;
  531. }
  532. checkStringPtr(info.name);
  533. checkStringPtr(info.label);
  534. checkStringPtr(info.maker);
  535. checkStringPtr(info.copyright);
  536. return &info;
  537. }
  538. // -------------------------------------------------------------------------------------------------------------------
  539. const char* carla_get_library_filename()
  540. {
  541. carla_debug("carla_get_library_filename()");
  542. static CarlaString ret;
  543. if (ret.isEmpty())
  544. {
  545. using juce::File;
  546. ret = File(File::getSpecialLocation(File::currentExecutableFile)).getFullPathName().toRawUTF8();
  547. }
  548. return ret;
  549. }
  550. const char* carla_get_library_folder()
  551. {
  552. carla_debug("carla_get_library_folder()");
  553. static CarlaString ret;
  554. if (ret.isEmpty())
  555. {
  556. using juce::File;
  557. ret = File(File::getSpecialLocation(File::currentExecutableFile).getParentDirectory()).getFullPathName().toRawUTF8();
  558. }
  559. return ret;
  560. }
  561. // -------------------------------------------------------------------------------------------------------------------