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.

1486 lines
46KB

  1. /*
  2. * Carla Plugin discovery
  3. * Copyright (C) 2011-2018 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 "CarlaBackendUtils.hpp"
  18. #include "CarlaLibUtils.hpp"
  19. #include "CarlaMathUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "LinkedList.hpp"
  22. #ifdef BUILD_BRIDGE
  23. # undef HAVE_FLUIDSYNTH
  24. #endif
  25. #include "CarlaLadspaUtils.hpp"
  26. #include "CarlaLv2Utils.hpp"
  27. #include "CarlaVstUtils.hpp"
  28. #ifdef CARLA_OS_MAC
  29. # import <Foundation/Foundation.h>
  30. #endif
  31. #ifdef HAVE_FLUIDSYNTH
  32. # include <fluidsynth.h>
  33. #endif
  34. #include <iostream>
  35. #ifndef BUILD_BRIDGE
  36. # include "water/files/File.h"
  37. # include "water/text/StringArray.h"
  38. # include "CarlaDssiUtils.cpp"
  39. # include "../backend/utils/CachedPlugins.cpp"
  40. #else
  41. # include "CarlaDssiUtils.hpp"
  42. #endif
  43. #define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl;
  44. using water::CharPointer_UTF8;
  45. using water::File;
  46. using water::StringArray;
  47. CARLA_BACKEND_USE_NAMESPACE
  48. // --------------------------------------------------------------------------
  49. // Dummy values to test plugins with
  50. static const uint32_t kBufferSize = 512;
  51. static const double kSampleRate = 44100.0;
  52. static const int32_t kSampleRatei = 44100;
  53. static const float kSampleRatef = 44100.0f;
  54. // --------------------------------------------------------------------------
  55. // Don't print ELF/EXE related errors since discovery can find multi-architecture binaries
  56. static void print_lib_error(const char* const filename)
  57. {
  58. const char* const error(lib_error(filename));
  59. if (error != nullptr &&
  60. std::strstr(error, "wrong ELF class") == nullptr &&
  61. std::strstr(error, "Bad EXE format") == nullptr &&
  62. std::strstr(error, "not a valid Win32 application") == nullptr)
  63. {
  64. DISCOVERY_OUT("error", error);
  65. }
  66. }
  67. // --------------------------------------------------------------------------
  68. // VST stuff
  69. // Check if plugin is currently processing
  70. static bool gVstIsProcessing = false;
  71. // Check if plugin needs idle
  72. static bool gVstNeedsIdle = false;
  73. // Check if plugin wants midi
  74. static bool gVstWantsMidi = false;
  75. // Check if plugin wants time
  76. static bool gVstWantsTime = false;
  77. // Current uniqueId for VST shell plugins
  78. static intptr_t gVstCurrentUniqueId = 0;
  79. // Supported Carla features
  80. static intptr_t vstHostCanDo(const char* const feature)
  81. {
  82. carla_debug("vstHostCanDo(\"%s\")", feature);
  83. if (std::strcmp(feature, "supplyIdle") == 0)
  84. return 1;
  85. if (std::strcmp(feature, "sendVstEvents") == 0)
  86. return 1;
  87. if (std::strcmp(feature, "sendVstMidiEvent") == 0)
  88. return 1;
  89. if (std::strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
  90. return 1;
  91. if (std::strcmp(feature, "sendVstTimeInfo") == 0)
  92. {
  93. gVstWantsTime = true;
  94. return 1;
  95. }
  96. if (std::strcmp(feature, "receiveVstEvents") == 0)
  97. return 1;
  98. if (std::strcmp(feature, "receiveVstMidiEvent") == 0)
  99. return 1;
  100. if (std::strcmp(feature, "receiveVstTimeInfo") == 0)
  101. return -1;
  102. if (std::strcmp(feature, "reportConnectionChanges") == 0)
  103. return -1;
  104. if (std::strcmp(feature, "acceptIOChanges") == 0)
  105. return 1;
  106. if (std::strcmp(feature, "sizeWindow") == 0)
  107. return 1;
  108. if (std::strcmp(feature, "offline") == 0)
  109. return -1;
  110. if (std::strcmp(feature, "openFileSelector") == 0)
  111. return -1;
  112. if (std::strcmp(feature, "closeFileSelector") == 0)
  113. return -1;
  114. if (std::strcmp(feature, "startStopProcess") == 0)
  115. return 1;
  116. if (std::strcmp(feature, "supportShell") == 0)
  117. return 1;
  118. if (std::strcmp(feature, "shellCategory") == 0)
  119. return 1;
  120. if (std::strcmp(feature, "NIMKPIVendorSpecificCallbacks") == 0)
  121. return -1;
  122. // non-official features found in some plugins:
  123. // "asyncProcessing"
  124. // "editFile"
  125. // unimplemented
  126. carla_stderr("vstHostCanDo(\"%s\") - unknown feature", feature);
  127. return 0;
  128. }
  129. // Host-side callback
  130. static intptr_t VSTCALLBACK vstHostCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  131. {
  132. carla_debug("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)", effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, opt);
  133. static VstTimeInfo timeInfo;
  134. intptr_t ret = 0;
  135. switch (opcode)
  136. {
  137. case audioMasterAutomate:
  138. ret = 1;
  139. break;
  140. case audioMasterVersion:
  141. ret = kVstVersion;
  142. break;
  143. case audioMasterCurrentId:
  144. ret = gVstCurrentUniqueId;
  145. break;
  146. case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
  147. if (gVstWantsMidi) { DISCOVERY_OUT("warning", "Plugin requested MIDI more than once"); }
  148. gVstWantsMidi = true;
  149. ret = 1;
  150. break;
  151. case audioMasterGetTime:
  152. if (! gVstIsProcessing) { DISCOVERY_OUT("warning", "Plugin requested timeInfo out of process"); }
  153. if (! gVstWantsTime) { DISCOVERY_OUT("warning", "Plugin requested timeInfo but didn't ask if host could do \"sendVstTimeInfo\""); }
  154. carla_zeroStruct(timeInfo);
  155. timeInfo.sampleRate = kSampleRate;
  156. // Tempo
  157. timeInfo.tempo = 120.0;
  158. timeInfo.flags |= kVstTempoValid;
  159. // Time Signature
  160. timeInfo.timeSigNumerator = 4;
  161. timeInfo.timeSigDenominator = 4;
  162. timeInfo.flags |= kVstTimeSigValid;
  163. ret = (intptr_t)&timeInfo;
  164. break;
  165. case DECLARE_VST_DEPRECATED(audioMasterTempoAt):
  166. ret = 120 * 10000;
  167. break;
  168. case DECLARE_VST_DEPRECATED(audioMasterGetNumAutomatableParameters):
  169. ret = carla_minPositive(effect->numParams, static_cast<int>(MAX_DEFAULT_PARAMETERS));
  170. break;
  171. case DECLARE_VST_DEPRECATED(audioMasterGetParameterQuantization):
  172. ret = 1; // full single float precision
  173. break;
  174. case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
  175. if (gVstNeedsIdle) { DISCOVERY_OUT("warning", "Plugin requested idle more than once"); }
  176. gVstNeedsIdle = true;
  177. ret = 1;
  178. break;
  179. case audioMasterGetSampleRate:
  180. ret = kSampleRatei;
  181. break;
  182. case audioMasterGetBlockSize:
  183. ret = kBufferSize;
  184. break;
  185. case DECLARE_VST_DEPRECATED(audioMasterWillReplaceOrAccumulate):
  186. ret = 1; // replace
  187. break;
  188. case audioMasterGetCurrentProcessLevel:
  189. ret = gVstIsProcessing ? kVstProcessLevelRealtime : kVstProcessLevelUser;
  190. break;
  191. case audioMasterGetAutomationState:
  192. ret = kVstAutomationOff;
  193. break;
  194. case audioMasterGetVendorString:
  195. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  196. std::strcpy((char*)ptr, "falkTX");
  197. ret = 1;
  198. break;
  199. case audioMasterGetProductString:
  200. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  201. std::strcpy((char*)ptr, "Carla-Discovery");
  202. ret = 1;
  203. break;
  204. case audioMasterGetVendorVersion:
  205. ret = CARLA_VERSION_HEX;
  206. break;
  207. case audioMasterCanDo:
  208. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  209. ret = vstHostCanDo((const char*)ptr);
  210. break;
  211. case audioMasterGetLanguage:
  212. ret = kVstLangEnglish;
  213. break;
  214. default:
  215. carla_stdout("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)", effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, opt);
  216. break;
  217. }
  218. return ret;
  219. }
  220. // ------------------------------ Plugin Checks -----------------------------
  221. #ifndef BUILD_BRIDGE
  222. static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo)
  223. {
  224. if (! pinfo->valid)
  225. return;
  226. DISCOVERY_OUT("init", "-----------");
  227. DISCOVERY_OUT("build", BINARY_NATIVE);
  228. DISCOVERY_OUT("hints", pinfo->hints);
  229. DISCOVERY_OUT("name", pinfo->name);
  230. DISCOVERY_OUT("maker", pinfo->maker);
  231. DISCOVERY_OUT("label", pinfo->label);
  232. DISCOVERY_OUT("audio.ins", pinfo->audioIns);
  233. DISCOVERY_OUT("audio.outs", pinfo->audioOuts);
  234. DISCOVERY_OUT("midi.ins", pinfo->midiIns);
  235. DISCOVERY_OUT("midi.outs", pinfo->midiOuts);
  236. DISCOVERY_OUT("parameters.ins", pinfo->parameterIns);
  237. DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts);
  238. DISCOVERY_OUT("end", "------------");
  239. }
  240. static void do_cached_check(const PluginType type)
  241. {
  242. const char* plugPath;
  243. switch (type)
  244. {
  245. case PLUGIN_LV2:
  246. plugPath = std::getenv("LV2_PATH");
  247. break;
  248. case PLUGIN_SFZ:
  249. plugPath = std::getenv("SFZ_PATH");
  250. break;
  251. default:
  252. plugPath = nullptr;
  253. break;
  254. }
  255. const uint count = carla_get_cached_plugin_count(type, plugPath);
  256. for (uint i=0; i<count; ++i)
  257. {
  258. const CarlaCachedPluginInfo* pinfo(carla_get_cached_plugin_info(type, i));
  259. CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr);
  260. print_cached_plugin(pinfo);
  261. }
  262. }
  263. #endif
  264. static void do_ladspa_check(lib_t& libHandle, const char* const filename, const bool doInit)
  265. {
  266. LADSPA_Descriptor_Function descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  267. if (descFn == nullptr)
  268. {
  269. DISCOVERY_OUT("error", "Not a LADSPA plugin");
  270. return;
  271. }
  272. const LADSPA_Descriptor* descriptor;
  273. {
  274. descriptor = descFn(0);
  275. if (descriptor == nullptr)
  276. {
  277. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  278. return;
  279. }
  280. if (doInit && descriptor->instantiate != nullptr && descriptor->cleanup != nullptr)
  281. {
  282. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  283. if (handle == nullptr)
  284. {
  285. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  286. return;
  287. }
  288. descriptor->cleanup(handle);
  289. lib_close(libHandle);
  290. libHandle = lib_open(filename);
  291. if (libHandle == nullptr)
  292. {
  293. print_lib_error(filename);
  294. return;
  295. }
  296. descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  297. if (descFn == nullptr)
  298. {
  299. DISCOVERY_OUT("error", "Not a LADSPA plugin (#2)");
  300. return;
  301. }
  302. }
  303. }
  304. unsigned long i = 0;
  305. while ((descriptor = descFn(i++)) != nullptr)
  306. {
  307. if (descriptor->instantiate == nullptr)
  308. {
  309. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no instantiate()");
  310. continue;
  311. }
  312. if (descriptor->cleanup == nullptr)
  313. {
  314. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no cleanup()");
  315. continue;
  316. }
  317. if (descriptor->run == nullptr)
  318. {
  319. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no run()");
  320. continue;
  321. }
  322. if (! LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  323. {
  324. DISCOVERY_OUT("warning", "Plugin '" << descriptor->Name << "' is not hard real-time capable");
  325. }
  326. uint hints = 0x0;
  327. int audioIns = 0;
  328. int audioOuts = 0;
  329. int audioTotal = 0;
  330. int parametersIns = 0;
  331. int parametersOuts = 0;
  332. int parametersTotal = 0;
  333. if (LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  334. hints |= PLUGIN_IS_RTSAFE;
  335. for (unsigned long j=0; j < descriptor->PortCount; ++j)
  336. {
  337. CARLA_ASSERT(descriptor->PortNames[j] != nullptr);
  338. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  339. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  340. {
  341. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  342. audioIns += 1;
  343. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  344. audioOuts += 1;
  345. audioTotal += 1;
  346. }
  347. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  348. {
  349. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  350. parametersIns += 1;
  351. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(descriptor->PortNames[j], "latency") != 0 && std::strcmp(descriptor->PortNames[j], "_latency") != 0)
  352. parametersOuts += 1;
  353. parametersTotal += 1;
  354. }
  355. }
  356. if (doInit)
  357. {
  358. // -----------------------------------------------------------------------
  359. // start crash-free plugin test
  360. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  361. if (handle == nullptr)
  362. {
  363. DISCOVERY_OUT("error", "Failed to init LADSPA plugin");
  364. continue;
  365. }
  366. // Test quick init and cleanup
  367. descriptor->cleanup(handle);
  368. handle = descriptor->instantiate(descriptor, kSampleRatei);
  369. if (handle == nullptr)
  370. {
  371. DISCOVERY_OUT("error", "Failed to init LADSPA plugin (#2)");
  372. continue;
  373. }
  374. LADSPA_Data bufferAudio[kBufferSize][audioTotal];
  375. LADSPA_Data bufferParams[parametersTotal];
  376. LADSPA_Data min, max, def;
  377. for (unsigned long j=0, iA=0, iC=0; j < descriptor->PortCount; ++j)
  378. {
  379. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  380. const LADSPA_PortRangeHint portRangeHints = descriptor->PortRangeHints[j];
  381. const char* const portName = descriptor->PortNames[j];
  382. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  383. {
  384. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  385. descriptor->connect_port(handle, j, bufferAudio[iA++]);
  386. }
  387. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  388. {
  389. // min value
  390. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  391. min = portRangeHints.LowerBound;
  392. else
  393. min = 0.0f;
  394. // max value
  395. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  396. max = portRangeHints.UpperBound;
  397. else
  398. max = 1.0f;
  399. if (min > max)
  400. {
  401. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  402. max = min + 0.1f;
  403. }
  404. else if (carla_isEqual(min, max))
  405. {
  406. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  407. max = min + 0.1f;
  408. }
  409. // default value
  410. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  411. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  412. {
  413. min *= kSampleRatef;
  414. max *= kSampleRatef;
  415. def *= kSampleRatef;
  416. }
  417. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  418. {
  419. // latency parameter
  420. def = 0.0f;
  421. }
  422. else
  423. {
  424. if (def < min)
  425. def = min;
  426. else if (def > max)
  427. def = max;
  428. }
  429. bufferParams[iC] = def;
  430. descriptor->connect_port(handle, j, &bufferParams[iC++]);
  431. }
  432. }
  433. if (descriptor->activate != nullptr)
  434. descriptor->activate(handle);
  435. descriptor->run(handle, kBufferSize);
  436. if (descriptor->deactivate != nullptr)
  437. descriptor->deactivate(handle);
  438. descriptor->cleanup(handle);
  439. // end crash-free plugin test
  440. // -----------------------------------------------------------------------
  441. }
  442. DISCOVERY_OUT("init", "-----------");
  443. DISCOVERY_OUT("build", BINARY_NATIVE);
  444. DISCOVERY_OUT("hints", hints);
  445. DISCOVERY_OUT("name", descriptor->Name);
  446. DISCOVERY_OUT("label", descriptor->Label);
  447. DISCOVERY_OUT("maker", descriptor->Maker);
  448. DISCOVERY_OUT("uniqueId", descriptor->UniqueID);
  449. DISCOVERY_OUT("audio.ins", audioIns);
  450. DISCOVERY_OUT("audio.outs", audioOuts);
  451. DISCOVERY_OUT("parameters.ins", parametersIns);
  452. DISCOVERY_OUT("parameters.outs", parametersOuts);
  453. DISCOVERY_OUT("end", "------------");
  454. }
  455. }
  456. static void do_dssi_check(lib_t& libHandle, const char* const filename, const bool doInit)
  457. {
  458. DSSI_Descriptor_Function descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  459. if (descFn == nullptr)
  460. {
  461. DISCOVERY_OUT("error", "Not a DSSI plugin");
  462. return;
  463. }
  464. const DSSI_Descriptor* descriptor;
  465. {
  466. descriptor = descFn(0);
  467. if (descriptor == nullptr)
  468. {
  469. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  470. return;
  471. }
  472. const LADSPA_Descriptor* const ldescriptor(descriptor->LADSPA_Plugin);
  473. if (ldescriptor == nullptr)
  474. {
  475. DISCOVERY_OUT("error", "DSSI plugin doesn't provide the LADSPA interface");
  476. return;
  477. }
  478. if (doInit && ldescriptor->instantiate != nullptr && ldescriptor->cleanup != nullptr)
  479. {
  480. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  481. if (handle == nullptr)
  482. {
  483. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  484. return;
  485. }
  486. ldescriptor->cleanup(handle);
  487. lib_close(libHandle);
  488. libHandle = lib_open(filename);
  489. if (libHandle == nullptr)
  490. {
  491. print_lib_error(filename);
  492. return;
  493. }
  494. descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  495. if (descFn == nullptr)
  496. {
  497. DISCOVERY_OUT("error", "Not a DSSI plugin (#2)");
  498. return;
  499. }
  500. }
  501. }
  502. unsigned long i = 0;
  503. while ((descriptor = descFn(i++)) != nullptr)
  504. {
  505. const LADSPA_Descriptor* const ldescriptor(descriptor->LADSPA_Plugin);
  506. if (ldescriptor == nullptr)
  507. {
  508. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no LADSPA interface");
  509. continue;
  510. }
  511. if (descriptor->DSSI_API_Version != DSSI_VERSION_MAJOR)
  512. {
  513. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' uses an unsupported DSSI spec version " << descriptor->DSSI_API_Version);
  514. continue;
  515. }
  516. if (ldescriptor->instantiate == nullptr)
  517. {
  518. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no instantiate()");
  519. continue;
  520. }
  521. if (ldescriptor->cleanup == nullptr)
  522. {
  523. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no cleanup()");
  524. continue;
  525. }
  526. if (ldescriptor->run == nullptr && descriptor->run_synth == nullptr)
  527. {
  528. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no run() or run_synth()");
  529. continue;
  530. }
  531. if (descriptor->run_synth == nullptr && descriptor->run_multiple_synths != nullptr)
  532. {
  533. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' requires run_multiple_synths which is not supported");
  534. continue;
  535. }
  536. if (! LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  537. {
  538. DISCOVERY_OUT("warning", "Plugin '" << ldescriptor->Name << "' is not hard real-time capable");
  539. }
  540. uint hints = 0x0;
  541. int audioIns = 0;
  542. int audioOuts = 0;
  543. int audioTotal = 0;
  544. int midiIns = 0;
  545. int parametersIns = 0;
  546. int parametersOuts = 0;
  547. int parametersTotal = 0;
  548. if (LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  549. hints |= PLUGIN_IS_RTSAFE;
  550. for (unsigned long j=0; j < ldescriptor->PortCount; ++j)
  551. {
  552. CARLA_ASSERT(ldescriptor->PortNames[j] != nullptr);
  553. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  554. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  555. {
  556. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  557. audioIns += 1;
  558. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  559. audioOuts += 1;
  560. audioTotal += 1;
  561. }
  562. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  563. {
  564. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  565. parametersIns += 1;
  566. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(ldescriptor->PortNames[j], "latency") != 0 && std::strcmp(ldescriptor->PortNames[j], "_latency") != 0)
  567. parametersOuts += 1;
  568. parametersTotal += 1;
  569. }
  570. }
  571. if (descriptor->run_synth != nullptr)
  572. midiIns = 1;
  573. if (midiIns > 0 && audioIns == 0 && audioOuts > 0)
  574. hints |= PLUGIN_IS_SYNTH;
  575. #ifndef BUILD_BRIDGE
  576. if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label))
  577. {
  578. hints |= PLUGIN_HAS_CUSTOM_UI;
  579. delete[] ui;
  580. }
  581. #endif
  582. if (doInit)
  583. {
  584. // -----------------------------------------------------------------------
  585. // start crash-free plugin test
  586. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  587. if (handle == nullptr)
  588. {
  589. DISCOVERY_OUT("error", "Failed to init DSSI plugin");
  590. continue;
  591. }
  592. // Test quick init and cleanup
  593. ldescriptor->cleanup(handle);
  594. handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  595. if (handle == nullptr)
  596. {
  597. DISCOVERY_OUT("error", "Failed to init DSSI plugin (#2)");
  598. continue;
  599. }
  600. LADSPA_Data bufferAudio[kBufferSize][audioTotal];
  601. LADSPA_Data bufferParams[parametersTotal];
  602. LADSPA_Data min, max, def;
  603. for (unsigned long j=0, iA=0, iC=0; j < ldescriptor->PortCount; ++j)
  604. {
  605. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  606. const LADSPA_PortRangeHint portRangeHints = ldescriptor->PortRangeHints[j];
  607. const char* const portName = ldescriptor->PortNames[j];
  608. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  609. {
  610. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  611. ldescriptor->connect_port(handle, j, bufferAudio[iA++]);
  612. }
  613. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  614. {
  615. // min value
  616. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  617. min = portRangeHints.LowerBound;
  618. else
  619. min = 0.0f;
  620. // max value
  621. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  622. max = portRangeHints.UpperBound;
  623. else
  624. max = 1.0f;
  625. if (min > max)
  626. {
  627. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  628. max = min + 0.1f;
  629. }
  630. else if (carla_isEqual(min, max))
  631. {
  632. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  633. max = min + 0.1f;
  634. }
  635. // default value
  636. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  637. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  638. {
  639. min *= kSampleRatef;
  640. max *= kSampleRatef;
  641. def *= kSampleRatef;
  642. }
  643. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  644. {
  645. // latency parameter
  646. def = 0.0f;
  647. }
  648. else
  649. {
  650. if (def < min)
  651. def = min;
  652. else if (def > max)
  653. def = max;
  654. }
  655. bufferParams[iC] = def;
  656. ldescriptor->connect_port(handle, j, &bufferParams[iC++]);
  657. }
  658. }
  659. // select first midi-program if available
  660. if (descriptor->get_program != nullptr && descriptor->select_program != nullptr)
  661. {
  662. if (const DSSI_Program_Descriptor* const pDesc = descriptor->get_program(handle, 0))
  663. descriptor->select_program(handle, pDesc->Bank, pDesc->Program);
  664. }
  665. if (ldescriptor->activate != nullptr)
  666. ldescriptor->activate(handle);
  667. if (descriptor->run_synth != nullptr)
  668. {
  669. snd_seq_event_t midiEvents[2];
  670. carla_zeroStructs(midiEvents, 2);
  671. const unsigned long midiEventCount = 2;
  672. midiEvents[0].type = SND_SEQ_EVENT_NOTEON;
  673. midiEvents[0].data.note.note = 64;
  674. midiEvents[0].data.note.velocity = 100;
  675. midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF;
  676. midiEvents[1].data.note.note = 64;
  677. midiEvents[1].data.note.velocity = 0;
  678. midiEvents[1].time.tick = kBufferSize/2;
  679. descriptor->run_synth(handle, kBufferSize, midiEvents, midiEventCount);
  680. }
  681. else
  682. ldescriptor->run(handle, kBufferSize);
  683. if (ldescriptor->deactivate != nullptr)
  684. ldescriptor->deactivate(handle);
  685. ldescriptor->cleanup(handle);
  686. // end crash-free plugin test
  687. // -----------------------------------------------------------------------
  688. }
  689. DISCOVERY_OUT("init", "-----------");
  690. DISCOVERY_OUT("build", BINARY_NATIVE);
  691. DISCOVERY_OUT("hints", hints);
  692. DISCOVERY_OUT("name", ldescriptor->Name);
  693. DISCOVERY_OUT("label", ldescriptor->Label);
  694. DISCOVERY_OUT("maker", ldescriptor->Maker);
  695. DISCOVERY_OUT("uniqueId", ldescriptor->UniqueID);
  696. DISCOVERY_OUT("audio.ins", audioIns);
  697. DISCOVERY_OUT("audio.outs", audioOuts);
  698. DISCOVERY_OUT("midi.ins", midiIns);
  699. DISCOVERY_OUT("parameters.ins", parametersIns);
  700. DISCOVERY_OUT("parameters.outs", parametersOuts);
  701. DISCOVERY_OUT("end", "------------");
  702. }
  703. }
  704. #ifndef BUILD_BRIDGE
  705. static void do_lv2_check(const char* const bundle, const bool doInit)
  706. {
  707. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  708. Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, bundle));
  709. CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(),);
  710. CarlaString sBundle(bundleNode.as_uri());
  711. if (! sBundle.endsWith("/"))
  712. sBundle += "/";
  713. // Load bundle
  714. lv2World.load_bundle(sBundle);
  715. // Load plugins in this bundle
  716. const Lilv::Plugins lilvPlugins(lv2World.get_all_plugins());
  717. // Get all plugin URIs in this bundle
  718. StringArray URIs;
  719. LILV_FOREACH(plugins, it, lilvPlugins)
  720. {
  721. Lilv::Plugin lilvPlugin(lilv_plugins_get(lilvPlugins, it));
  722. if (const char* const uri = lilvPlugin.get_uri().as_string())
  723. URIs.addIfNotAlreadyThere(water::String(uri));
  724. }
  725. if (URIs.size() == 0)
  726. {
  727. DISCOVERY_OUT("warning", "LV2 Bundle doesn't provide any plugins");
  728. return;
  729. }
  730. // Get & check every plugin-instance
  731. for (int i=0, count=URIs.size(); i < count; ++i)
  732. {
  733. const char* const URI = URIs[i].toRawUTF8();
  734. ScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));
  735. if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr)
  736. {
  737. DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'");
  738. continue;
  739. }
  740. if (doInit)
  741. {
  742. // test if lib is loadable, twice
  743. const lib_t libHandle1 = lib_open(rdfDescriptor->Binary);
  744. if (libHandle1 == nullptr)
  745. {
  746. print_lib_error(rdfDescriptor->Binary);
  747. delete rdfDescriptor;
  748. continue;
  749. }
  750. lib_close(libHandle1);
  751. const lib_t libHandle2 = lib_open(rdfDescriptor->Binary);
  752. if (libHandle2 == nullptr)
  753. {
  754. print_lib_error(rdfDescriptor->Binary);
  755. delete rdfDescriptor;
  756. continue;
  757. }
  758. lib_close(libHandle2);
  759. }
  760. const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI));
  761. CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr);
  762. Lilv::Plugin lilvPlugin(cPlugin);
  763. CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri());
  764. print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin));
  765. }
  766. }
  767. #endif
  768. static void do_vst_check(lib_t& libHandle, const char* const filename, const bool doInit)
  769. {
  770. VST_Function vstFn = nullptr;
  771. #ifdef CARLA_OS_MAC
  772. CFBundleRef bundleRef = nullptr;
  773. CFBundleRefNum resFileId = 0;
  774. if (libHandle == nullptr)
  775. {
  776. const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)filename, (CFIndex)strlen(filename), true);
  777. CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr,);
  778. bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef);
  779. CFRelease(urlRef);
  780. CARLA_SAFE_ASSERT_RETURN(bundleRef != nullptr,);
  781. if (! CFBundleLoadExecutable(bundleRef))
  782. {
  783. CFRelease(bundleRef);
  784. DISCOVERY_OUT("error", "Failed to load VST bundle executable");
  785. return;
  786. }
  787. vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("main_macho"));
  788. if (vstFn == nullptr)
  789. vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("VSTPluginMain"));
  790. if (vstFn == nullptr)
  791. {
  792. CFBundleUnloadExecutable(bundleRef);
  793. CFRelease(bundleRef);
  794. DISCOVERY_OUT("error", "Not a VST plugin");
  795. return;
  796. }
  797. resFileId = CFBundleOpenBundleResourceMap(bundleRef);
  798. }
  799. else
  800. #endif
  801. {
  802. vstFn = lib_symbol<VST_Function>(libHandle, "VSTPluginMain");
  803. if (vstFn == nullptr)
  804. {
  805. vstFn = lib_symbol<VST_Function>(libHandle, "main");
  806. if (vstFn == nullptr)
  807. {
  808. DISCOVERY_OUT("error", "Not a VST plugin");
  809. return;
  810. }
  811. }
  812. }
  813. AEffect* effect = vstFn(vstHostCallback);
  814. if (effect == nullptr || effect->magic != kEffectMagic)
  815. {
  816. DISCOVERY_OUT("error", "Failed to init VST plugin, or VST magic failed");
  817. return;
  818. }
  819. if (effect->uniqueID == 0)
  820. {
  821. DISCOVERY_OUT("error", "Plugin doesn't have an Unique ID");
  822. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  823. return;
  824. }
  825. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  826. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  827. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  828. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  829. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  830. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  831. if (effect->numPrograms > 0)
  832. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  833. const bool isShell = (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f) == kPlugCategShell);
  834. gVstCurrentUniqueId = effect->uniqueID;
  835. char strBuf[STR_MAX+1];
  836. CarlaString cName;
  837. CarlaString cProduct;
  838. CarlaString cVendor;
  839. LinkedList<intptr_t> uniqueIds;
  840. if (isShell)
  841. {
  842. for (;;)
  843. {
  844. carla_zeroChars(strBuf, STR_MAX+1);
  845. gVstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, strBuf, 0.0f);
  846. if (gVstCurrentUniqueId == 0)
  847. break;
  848. uniqueIds.append(gVstCurrentUniqueId);
  849. }
  850. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  851. effect = nullptr;
  852. }
  853. else
  854. {
  855. uniqueIds.append(gVstCurrentUniqueId);
  856. }
  857. for (LinkedList<intptr_t>::Itenerator it = uniqueIds.begin2(); it.valid(); it.next())
  858. {
  859. gVstCurrentUniqueId = it.getValue(0);
  860. if (effect == nullptr)
  861. {
  862. effect = vstFn(vstHostCallback);
  863. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  864. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  865. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  866. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  867. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  868. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  869. if (effect->numPrograms > 0)
  870. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  871. }
  872. // get name
  873. carla_zeroChars(strBuf, STR_MAX+1);
  874. if (effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f) == 1)
  875. cName = strBuf;
  876. else
  877. cName.clear();
  878. // get product
  879. carla_zeroChars(strBuf, STR_MAX+1);
  880. if (effect->dispatcher(effect, effGetProductString, 0, 0, strBuf, 0.0f) == 1)
  881. cProduct = strBuf;
  882. else
  883. cProduct.clear();
  884. // get vendor
  885. carla_zeroChars(strBuf, STR_MAX+1);
  886. if (effect->dispatcher(effect, effGetVendorString, 0, 0, strBuf, 0.0f) == 1)
  887. cVendor = strBuf;
  888. else
  889. cVendor.clear();
  890. // get everything else
  891. uint hints = 0x0;
  892. int audioIns = effect->numInputs;
  893. int audioOuts = effect->numOutputs;
  894. int midiIns = 0;
  895. int midiOuts = 0;
  896. int parameters = effect->numParams;
  897. if (effect->flags & effFlagsHasEditor)
  898. hints |= PLUGIN_HAS_CUSTOM_UI;
  899. if (effect->flags & effFlagsIsSynth)
  900. hints |= PLUGIN_IS_SYNTH;
  901. if (vstPluginCanDo(effect, "receiveVstEvents") || vstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) != 0)
  902. midiIns = 1;
  903. if (vstPluginCanDo(effect, "sendVstEvents") || vstPluginCanDo(effect, "sendVstMidiEvent"))
  904. midiOuts = 1;
  905. // -----------------------------------------------------------------------
  906. // start crash-free plugin test
  907. if (doInit)
  908. {
  909. if (gVstNeedsIdle)
  910. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  911. effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f);
  912. effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f);
  913. if (gVstNeedsIdle)
  914. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  915. // Plugin might call wantMidi() during resume
  916. if (midiIns == 0 && gVstWantsMidi)
  917. {
  918. midiIns = 1;
  919. }
  920. float* bufferAudioIn[std::max(1, audioIns)];
  921. float* bufferAudioOut[std::max(1, audioOuts)];
  922. if (audioIns == 0)
  923. {
  924. bufferAudioIn[0] = nullptr;
  925. }
  926. else
  927. {
  928. for (int j=0; j < audioIns; ++j)
  929. {
  930. bufferAudioIn[j] = new float[kBufferSize];
  931. carla_zeroFloats(bufferAudioIn[j], kBufferSize);
  932. }
  933. }
  934. if (audioOuts == 0)
  935. {
  936. bufferAudioOut[0] = nullptr;
  937. }
  938. else
  939. {
  940. for (int j=0; j < audioOuts; ++j)
  941. {
  942. bufferAudioOut[j] = new float[kBufferSize];
  943. carla_zeroFloats(bufferAudioOut[j], kBufferSize);
  944. }
  945. }
  946. struct VstEventsFixed {
  947. int32_t numEvents;
  948. intptr_t reserved;
  949. VstEvent* data[2];
  950. VstEventsFixed()
  951. : numEvents(0),
  952. reserved(0)
  953. {
  954. data[0] = data[1] = nullptr;
  955. }
  956. } events;
  957. VstMidiEvent midiEvents[2];
  958. carla_zeroStructs(midiEvents, 2);
  959. midiEvents[0].type = kVstMidiType;
  960. midiEvents[0].byteSize = sizeof(VstMidiEvent);
  961. midiEvents[0].midiData[0] = char(MIDI_STATUS_NOTE_ON);
  962. midiEvents[0].midiData[1] = 64;
  963. midiEvents[0].midiData[2] = 100;
  964. midiEvents[1].type = kVstMidiType;
  965. midiEvents[1].byteSize = sizeof(VstMidiEvent);
  966. midiEvents[1].midiData[0] = char(MIDI_STATUS_NOTE_OFF);
  967. midiEvents[1].midiData[1] = 64;
  968. midiEvents[1].deltaFrames = kBufferSize/2;
  969. events.numEvents = 2;
  970. events.data[0] = (VstEvent*)&midiEvents[0];
  971. events.data[1] = (VstEvent*)&midiEvents[1];
  972. // processing
  973. gVstIsProcessing = true;
  974. if (midiIns > 0)
  975. effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f);
  976. if ((effect->flags & effFlagsCanReplacing) > 0 && effect->processReplacing != nullptr && effect->processReplacing != effect->DECLARE_VST_DEPRECATED(process))
  977. effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  978. else if (effect->DECLARE_VST_DEPRECATED(process) != nullptr)
  979. effect->DECLARE_VST_DEPRECATED(process)(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  980. else
  981. DISCOVERY_OUT("error", "Plugin doesn't have a process function");
  982. gVstIsProcessing = false;
  983. effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f);
  984. effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
  985. if (gVstNeedsIdle)
  986. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  987. for (int j=0; j < audioIns; ++j)
  988. delete[] bufferAudioIn[j];
  989. for (int j=0; j < audioOuts; ++j)
  990. delete[] bufferAudioOut[j];
  991. }
  992. // end crash-free plugin test
  993. // -----------------------------------------------------------------------
  994. DISCOVERY_OUT("init", "-----------");
  995. DISCOVERY_OUT("build", BINARY_NATIVE);
  996. DISCOVERY_OUT("hints", hints);
  997. DISCOVERY_OUT("name", cName.buffer());
  998. DISCOVERY_OUT("label", cProduct.buffer());
  999. DISCOVERY_OUT("maker", cVendor.buffer());
  1000. DISCOVERY_OUT("uniqueId", gVstCurrentUniqueId);
  1001. DISCOVERY_OUT("audio.ins", audioIns);
  1002. DISCOVERY_OUT("audio.outs", audioOuts);
  1003. DISCOVERY_OUT("midi.ins", midiIns);
  1004. DISCOVERY_OUT("midi.outs", midiOuts);
  1005. DISCOVERY_OUT("parameters.ins", parameters);
  1006. DISCOVERY_OUT("end", "------------");
  1007. gVstWantsMidi = false;
  1008. gVstWantsTime = false;
  1009. if (! isShell)
  1010. break;
  1011. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1012. effect = nullptr;
  1013. }
  1014. uniqueIds.clear();
  1015. if (effect != nullptr)
  1016. {
  1017. if (gVstNeedsIdle)
  1018. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1019. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1020. }
  1021. #ifdef CARLA_OS_MAC
  1022. if (bundleRef != nullptr)
  1023. {
  1024. CFBundleCloseBundleResourceMap(bundleRef, resFileId);
  1025. CFBundleUnloadExecutable(bundleRef);
  1026. CFRelease(bundleRef);
  1027. }
  1028. #else
  1029. return;
  1030. // unused
  1031. (void)filename;
  1032. #endif
  1033. }
  1034. static void do_fluidsynth_check(const char* const filename, const bool doInit)
  1035. {
  1036. #ifdef HAVE_FLUIDSYNTH
  1037. const water::String jfilename = water::String(CharPointer_UTF8(filename));
  1038. const File file(jfilename);
  1039. if (! file.existsAsFile())
  1040. {
  1041. DISCOVERY_OUT("error", "Requested file is not valid or does not exist");
  1042. return;
  1043. }
  1044. if (! fluid_is_soundfont(filename))
  1045. {
  1046. DISCOVERY_OUT("error", "Not a SF2 file");
  1047. return;
  1048. }
  1049. int programs = 0;
  1050. if (doInit)
  1051. {
  1052. fluid_settings_t* const f_settings = new_fluid_settings();
  1053. CARLA_SAFE_ASSERT_RETURN(f_settings != nullptr,);
  1054. fluid_synth_t* const f_synth = new_fluid_synth(f_settings);
  1055. CARLA_SAFE_ASSERT_RETURN(f_synth != nullptr,);
  1056. const int f_id = fluid_synth_sfload(f_synth, filename, 0);
  1057. if (f_id < 0)
  1058. {
  1059. DISCOVERY_OUT("error", "Failed to load SF2 file");
  1060. return;
  1061. }
  1062. if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, static_cast<uint>(f_id)))
  1063. {
  1064. fluid_preset_t f_preset;
  1065. f_sfont->iteration_start(f_sfont);
  1066. for (; f_sfont->iteration_next(f_sfont, &f_preset);)
  1067. ++programs;
  1068. }
  1069. delete_fluid_synth(f_synth);
  1070. delete_fluid_settings(f_settings);
  1071. }
  1072. CarlaString name(file.getFileNameWithoutExtension().toRawUTF8());
  1073. CarlaString label(name);
  1074. // 2 channels
  1075. DISCOVERY_OUT("init", "-----------");
  1076. DISCOVERY_OUT("build", BINARY_NATIVE);
  1077. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  1078. DISCOVERY_OUT("name", name.buffer());
  1079. DISCOVERY_OUT("label", label.buffer());
  1080. DISCOVERY_OUT("audio.outs", 2);
  1081. DISCOVERY_OUT("midi.ins", 1);
  1082. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  1083. DISCOVERY_OUT("parameters.outs", 1);
  1084. DISCOVERY_OUT("end", "------------");
  1085. // 16 channels
  1086. if (doInit && (name.isEmpty() || programs <= 1))
  1087. return;
  1088. name += " (16 outputs)";
  1089. DISCOVERY_OUT("init", "-----------");
  1090. DISCOVERY_OUT("build", BINARY_NATIVE);
  1091. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  1092. DISCOVERY_OUT("name", name.buffer());
  1093. DISCOVERY_OUT("label", label.buffer());
  1094. DISCOVERY_OUT("audio.outs", 32);
  1095. DISCOVERY_OUT("midi.ins", 1);
  1096. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  1097. DISCOVERY_OUT("parameters.outs", 1);
  1098. DISCOVERY_OUT("end", "------------");
  1099. #else // HAVE_FLUIDSYNTH
  1100. DISCOVERY_OUT("error", "SF2 support not available");
  1101. return;
  1102. // unused
  1103. (void)filename;
  1104. (void)doInit;
  1105. #endif
  1106. }
  1107. // ------------------------------ main entry point ------------------------------
  1108. int main(int argc, char* argv[])
  1109. {
  1110. if (argc != 3)
  1111. {
  1112. carla_stdout("usage: %s <type> </path/to/plugin>", argv[0]);
  1113. return 1;
  1114. }
  1115. const char* const stype = argv[1];
  1116. const char* const filename = argv[2];
  1117. const PluginType type = getPluginTypeFromString(stype);
  1118. CarlaString filenameCheck(filename);
  1119. filenameCheck.toLower();
  1120. bool openLib = false;
  1121. lib_t handle = nullptr;
  1122. switch (type)
  1123. {
  1124. case PLUGIN_LADSPA:
  1125. case PLUGIN_DSSI:
  1126. case PLUGIN_VST2:
  1127. openLib = true;
  1128. default:
  1129. break;
  1130. }
  1131. if (type != PLUGIN_SF2 && filenameCheck.contains("fluidsynth", true))
  1132. {
  1133. DISCOVERY_OUT("info", "skipping fluidsynth based plugin");
  1134. return 0;
  1135. }
  1136. #ifdef CARLA_OS_MAC
  1137. if (type == PLUGIN_VST2 && (filenameCheck.endsWith(".vst") || filenameCheck.endsWith(".vst/")))
  1138. openLib = false;
  1139. #endif
  1140. if (openLib)
  1141. {
  1142. handle = lib_open(filename);
  1143. if (handle == nullptr)
  1144. {
  1145. print_lib_error(filename);
  1146. return 1;
  1147. }
  1148. }
  1149. // never do init for dssi-vst, takes too long and it's crashy
  1150. bool doInit = ! filenameCheck.contains("dssi-vst", true);
  1151. if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") != nullptr)
  1152. doInit = false;
  1153. if (doInit && openLib && handle != nullptr)
  1154. {
  1155. // test fast loading & unloading DLL without initializing the plugin(s)
  1156. if (! lib_close(handle))
  1157. {
  1158. print_lib_error(filename);
  1159. return 1;
  1160. }
  1161. handle = lib_open(filename);
  1162. if (handle == nullptr)
  1163. {
  1164. print_lib_error(filename);
  1165. return 1;
  1166. }
  1167. }
  1168. #ifndef BUILD_BRIDGE
  1169. if (std::strcmp(filename, ":all") == 0)
  1170. {
  1171. do_cached_check(type);
  1172. return 0;
  1173. }
  1174. #endif
  1175. switch (type)
  1176. {
  1177. case PLUGIN_LADSPA:
  1178. do_ladspa_check(handle, filename, doInit);
  1179. break;
  1180. case PLUGIN_DSSI:
  1181. do_dssi_check(handle, filename, doInit);
  1182. break;
  1183. #ifndef BUILD_BRIDGE
  1184. case PLUGIN_LV2:
  1185. do_lv2_check(filename, doInit);
  1186. break;
  1187. #endif
  1188. case PLUGIN_VST2:
  1189. do_vst_check(handle, filename, doInit);
  1190. break;
  1191. case PLUGIN_SF2:
  1192. do_fluidsynth_check(filename, doInit);
  1193. break;
  1194. default:
  1195. break;
  1196. }
  1197. if (openLib && handle != nullptr)
  1198. lib_close(handle);
  1199. return 0;
  1200. }
  1201. // --------------------------------------------------------------------------