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.

3108 lines
104KB

  1. // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "CarlaBackendUtils.hpp"
  4. #include "CarlaLibUtils.hpp"
  5. #include "CarlaMathUtils.hpp"
  6. #include "CarlaScopeUtils.hpp"
  7. #include "CarlaMIDI.h"
  8. #include "LinkedList.hpp"
  9. #include "CarlaLadspaUtils.hpp"
  10. #include "CarlaDssiUtils.hpp"
  11. #include "CarlaLv2Utils.hpp"
  12. #include "CarlaVst2Utils.hpp"
  13. #include "CarlaVst3Utils.hpp"
  14. #include "CarlaClapUtils.hpp"
  15. #ifndef BUILDING_CARLA_FOR_WINE
  16. # include "CarlaPipeUtils.cpp"
  17. #endif
  18. #ifdef CARLA_OS_MAC
  19. # include "CarlaMacUtils.cpp"
  20. # include <AudioToolbox/AudioUnit.h>
  21. # ifdef __aarch64__
  22. # include <spawn.h>
  23. # endif
  24. # ifndef __MAC_13_0
  25. enum {
  26. kAudioUnitType_SpeechSynthesizer = 'ausp',
  27. };
  28. # endif
  29. #endif
  30. #ifdef CARLA_OS_WIN
  31. # include <pthread.h>
  32. # include <objbase.h>
  33. #endif
  34. #ifdef BUILD_BRIDGE
  35. # undef HAVE_FLUIDSYNTH
  36. # undef HAVE_YSFX
  37. #endif
  38. #ifdef HAVE_FLUIDSYNTH
  39. # include <fluidsynth.h>
  40. #endif
  41. #include <iostream>
  42. #include <sstream>
  43. #include "water/files/File.h"
  44. #ifndef BUILD_BRIDGE
  45. # include "CarlaDssiUtils.cpp"
  46. # include "CarlaJsfxUtils.hpp"
  47. # include "../backend/utils/CachedPlugins.cpp"
  48. #endif
  49. // must be last
  50. #ifdef BUILDING_CARLA_FOR_WINE
  51. # include "../jackbridge/JackBridge.hpp"
  52. #endif
  53. #define MAX_DISCOVERY_AUDIO_IO 64
  54. #define MAX_DISCOVERY_CV_IO 32
  55. #define DISCOVERY_OUT(x, y) \
  56. if (gPipe != nullptr) { std::stringstream s; s << y; gPipe->writeDiscoveryMessage(x, s.str().c_str()); } \
  57. else { std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl; }
  58. using water::File;
  59. CARLA_BACKEND_USE_NAMESPACE
  60. // --------------------------------------------------------------------------------------------------------------------
  61. // Dummy values to test plugins with
  62. static constexpr const uint32_t kBufferSize = 512;
  63. static constexpr const double kSampleRate = 44100.0;
  64. static constexpr const int32_t kSampleRatei = 44100;
  65. static constexpr const float kSampleRatef = 44100.0f;
  66. // --------------------------------------------------------------------------------------------------------------------
  67. // Dynamic discovery
  68. #ifndef BUILDING_CARLA_FOR_WINE
  69. class DiscoveryPipe : public CarlaPipeClient
  70. {
  71. public:
  72. DiscoveryPipe() {}
  73. ~DiscoveryPipe()
  74. {
  75. writeExitingMessageAndWait();
  76. }
  77. bool writeDiscoveryMessage(const char* const key, const char* const value) const noexcept
  78. {
  79. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
  80. CARLA_SAFE_ASSERT_RETURN(value != nullptr, false);
  81. const CarlaMutexLocker cml(pData->writeLock);
  82. if (! writeAndFixMessage(key))
  83. return false;
  84. if (! writeAndFixMessage(value))
  85. return false;
  86. syncMessages();
  87. return true;
  88. }
  89. protected:
  90. bool msgReceived(const char* const msg) noexcept
  91. {
  92. carla_stdout("discovery msgReceived %s", msg);
  93. return true;
  94. }
  95. };
  96. #else
  97. class DiscoveryPipe
  98. {
  99. void* pipe;
  100. public:
  101. DiscoveryPipe() noexcept : pipe(nullptr) {}
  102. ~DiscoveryPipe()
  103. {
  104. if (pipe != nullptr)
  105. jackbridge_discovery_pipe_destroy(pipe);
  106. }
  107. bool initPipeClient(const char* argv[])
  108. {
  109. if (jackbridge_is_ok())
  110. pipe = jackbridge_discovery_pipe_create(argv);
  111. return pipe != nullptr;
  112. }
  113. bool writeDiscoveryMessage(const char* const key, const char* const value) const noexcept
  114. {
  115. CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0', false);
  116. CARLA_SAFE_ASSERT_RETURN(value != nullptr, false);
  117. jackbridge_discovery_pipe_message(pipe, key, value);
  118. return true;
  119. }
  120. };
  121. #endif
  122. CarlaScopedPointer<DiscoveryPipe> gPipe;
  123. // --------------------------------------------------------------------------------------------------------------------
  124. // Don't print ELF/EXE related errors since discovery can find multi-architecture binaries
  125. static void print_lib_error(const char* const filename)
  126. {
  127. const char* const error = lib_error(filename);
  128. if (error != nullptr &&
  129. std::strstr(error, "wrong ELF class") == nullptr &&
  130. std::strstr(error, "invalid ELF header") == nullptr &&
  131. std::strstr(error, "Bad EXE format") == nullptr &&
  132. std::strstr(error, "no suitable image found") == nullptr &&
  133. std::strstr(error, "not a valid Win32 application") == nullptr)
  134. {
  135. DISCOVERY_OUT("error", error);
  136. }
  137. }
  138. #ifdef CARLA_OS_WIN
  139. // --------------------------------------------------------------------------------------------------------------------
  140. // Do not show error message box on Windows
  141. static LONG WINAPI winExceptionFilter(_EXCEPTION_POINTERS*)
  142. {
  143. return EXCEPTION_EXECUTE_HANDLER;
  144. }
  145. #endif
  146. // --------------------------------------------------------------------------------------------------------------------
  147. // Carla Cached API
  148. #ifndef BUILD_BRIDGE
  149. static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo)
  150. {
  151. if (! pinfo->valid)
  152. return;
  153. DISCOVERY_OUT("init", "------------");
  154. DISCOVERY_OUT("build", BINARY_NATIVE);
  155. DISCOVERY_OUT("hints", pinfo->hints);
  156. DISCOVERY_OUT("category", getPluginCategoryAsString(pinfo->category));
  157. DISCOVERY_OUT("name", pinfo->name);
  158. DISCOVERY_OUT("maker", pinfo->maker);
  159. DISCOVERY_OUT("label", pinfo->label);
  160. DISCOVERY_OUT("audio.ins", pinfo->audioIns);
  161. DISCOVERY_OUT("audio.outs", pinfo->audioOuts);
  162. DISCOVERY_OUT("cv.ins", pinfo->cvIns);
  163. DISCOVERY_OUT("cv.outs", pinfo->cvOuts);
  164. DISCOVERY_OUT("midi.ins", pinfo->midiIns);
  165. DISCOVERY_OUT("midi.outs", pinfo->midiOuts);
  166. DISCOVERY_OUT("parameters.ins", pinfo->parameterIns);
  167. DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts);
  168. DISCOVERY_OUT("end", "------------");
  169. }
  170. static void do_cached_check(const PluginType type)
  171. {
  172. const char* plugPath = std::getenv("CARLA_DISCOVERY_PATH");
  173. if (plugPath == nullptr)
  174. {
  175. switch (type)
  176. {
  177. case PLUGIN_LV2:
  178. plugPath = std::getenv("LV2_PATH");
  179. break;
  180. case PLUGIN_SFZ:
  181. plugPath = std::getenv("SFZ_PATH");
  182. break;
  183. default:
  184. plugPath = nullptr;
  185. break;
  186. }
  187. }
  188. const uint count = carla_get_cached_plugin_count(type, plugPath);
  189. for (uint i=0; i<count; ++i)
  190. {
  191. const CarlaCachedPluginInfo* pinfo = carla_get_cached_plugin_info(type, i);
  192. CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr);
  193. print_cached_plugin(pinfo);
  194. }
  195. }
  196. #endif // ! BUILD_BRIDGE
  197. // --------------------------------------------------------------------------------------------------------------------
  198. // LADSPA
  199. static void do_ladspa_check(lib_t& libHandle, const char* const filename, const bool doInit)
  200. {
  201. LADSPA_Descriptor_Function descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  202. if (descFn == nullptr)
  203. {
  204. DISCOVERY_OUT("error", "Not a LADSPA plugin");
  205. return;
  206. }
  207. const LADSPA_Descriptor* descriptor;
  208. {
  209. descriptor = descFn(0);
  210. if (descriptor == nullptr)
  211. {
  212. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  213. return;
  214. }
  215. if (doInit && descriptor->instantiate != nullptr && descriptor->cleanup != nullptr)
  216. {
  217. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  218. if (handle == nullptr)
  219. {
  220. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  221. return;
  222. }
  223. descriptor->cleanup(handle);
  224. lib_close(libHandle);
  225. libHandle = lib_open(filename);
  226. if (libHandle == nullptr)
  227. {
  228. print_lib_error(filename);
  229. return;
  230. }
  231. descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  232. if (descFn == nullptr)
  233. {
  234. DISCOVERY_OUT("error", "Not a LADSPA plugin (#2)");
  235. return;
  236. }
  237. }
  238. }
  239. unsigned long i = 0;
  240. while ((descriptor = descFn(i++)) != nullptr)
  241. {
  242. if (descriptor->instantiate == nullptr)
  243. {
  244. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no instantiate()");
  245. continue;
  246. }
  247. if (descriptor->cleanup == nullptr)
  248. {
  249. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no cleanup()");
  250. continue;
  251. }
  252. if (descriptor->run == nullptr)
  253. {
  254. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no run()");
  255. continue;
  256. }
  257. if (! LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  258. {
  259. DISCOVERY_OUT("warning", "Plugin '" << descriptor->Name << "' is not hard real-time capable");
  260. }
  261. uint hints = 0x0;
  262. uint audioIns = 0;
  263. uint audioOuts = 0;
  264. uint parametersIns = 0;
  265. uint parametersOuts = 0;
  266. uint parametersTotal = 0;
  267. if (LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  268. hints |= PLUGIN_IS_RTSAFE;
  269. for (unsigned long j=0; j < descriptor->PortCount; ++j)
  270. {
  271. CARLA_ASSERT(descriptor->PortNames[j] != nullptr);
  272. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  273. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  274. {
  275. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  276. audioIns += 1;
  277. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  278. audioOuts += 1;
  279. }
  280. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  281. {
  282. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  283. parametersIns += 1;
  284. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(descriptor->PortNames[j], "latency") != 0 && std::strcmp(descriptor->PortNames[j], "_latency") != 0)
  285. parametersOuts += 1;
  286. parametersTotal += 1;
  287. }
  288. }
  289. CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
  290. CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
  291. if (doInit)
  292. {
  293. // -----------------------------------------------------------------------
  294. // start crash-free plugin test
  295. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  296. if (handle == nullptr)
  297. {
  298. DISCOVERY_OUT("error", "Failed to init LADSPA plugin");
  299. continue;
  300. }
  301. // Test quick init and cleanup
  302. descriptor->cleanup(handle);
  303. handle = descriptor->instantiate(descriptor, kSampleRatei);
  304. if (handle == nullptr)
  305. {
  306. DISCOVERY_OUT("error", "Failed to init LADSPA plugin (#2)");
  307. continue;
  308. }
  309. LADSPA_Data* bufferParams = new LADSPA_Data[parametersTotal];
  310. LADSPA_Data bufferAudio[kBufferSize][MAX_DISCOVERY_AUDIO_IO];
  311. LADSPA_Data min, max, def;
  312. for (unsigned long j=0, iA=0, iC=0; j < descriptor->PortCount; ++j)
  313. {
  314. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  315. const LADSPA_PortRangeHint portRangeHints = descriptor->PortRangeHints[j];
  316. const char* const portName = descriptor->PortNames[j];
  317. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  318. {
  319. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  320. descriptor->connect_port(handle, j, bufferAudio[iA++]);
  321. }
  322. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  323. {
  324. // min value
  325. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  326. min = portRangeHints.LowerBound;
  327. else
  328. min = 0.0f;
  329. // max value
  330. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  331. max = portRangeHints.UpperBound;
  332. else
  333. max = 1.0f;
  334. if (min > max)
  335. {
  336. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  337. max = min + 0.1f;
  338. }
  339. else if (carla_isEqual(min, max))
  340. {
  341. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  342. max = min + 0.1f;
  343. }
  344. // default value
  345. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  346. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  347. {
  348. min *= kSampleRatef;
  349. max *= kSampleRatef;
  350. def *= kSampleRatef;
  351. }
  352. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  353. {
  354. // latency parameter
  355. def = 0.0f;
  356. }
  357. else
  358. {
  359. if (def < min)
  360. def = min;
  361. else if (def > max)
  362. def = max;
  363. }
  364. bufferParams[iC] = def;
  365. descriptor->connect_port(handle, j, &bufferParams[iC++]);
  366. }
  367. }
  368. if (descriptor->activate != nullptr)
  369. descriptor->activate(handle);
  370. descriptor->run(handle, kBufferSize);
  371. if (descriptor->deactivate != nullptr)
  372. descriptor->deactivate(handle);
  373. descriptor->cleanup(handle);
  374. delete[] bufferParams;
  375. // end crash-free plugin test
  376. // -----------------------------------------------------------------------
  377. }
  378. DISCOVERY_OUT("init", "------------");
  379. DISCOVERY_OUT("build", BINARY_NATIVE);
  380. DISCOVERY_OUT("hints", hints);
  381. DISCOVERY_OUT("category", getPluginCategoryAsString(getPluginCategoryFromName(descriptor->Name)));
  382. DISCOVERY_OUT("name", descriptor->Name);
  383. DISCOVERY_OUT("label", descriptor->Label);
  384. DISCOVERY_OUT("maker", descriptor->Maker);
  385. DISCOVERY_OUT("uniqueId", descriptor->UniqueID);
  386. DISCOVERY_OUT("audio.ins", audioIns);
  387. DISCOVERY_OUT("audio.outs", audioOuts);
  388. DISCOVERY_OUT("parameters.ins", parametersIns);
  389. DISCOVERY_OUT("parameters.outs", parametersOuts);
  390. DISCOVERY_OUT("end", "------------");
  391. }
  392. }
  393. // --------------------------------------------------------------------------------------------------------------------
  394. // DSSI
  395. static void do_dssi_check(lib_t& libHandle, const char* const filename, const bool doInit)
  396. {
  397. DSSI_Descriptor_Function descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  398. if (descFn == nullptr)
  399. {
  400. DISCOVERY_OUT("error", "Not a DSSI plugin");
  401. return;
  402. }
  403. const DSSI_Descriptor* descriptor;
  404. {
  405. descriptor = descFn(0);
  406. if (descriptor == nullptr)
  407. {
  408. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  409. return;
  410. }
  411. const LADSPA_Descriptor* const ldescriptor(descriptor->LADSPA_Plugin);
  412. if (ldescriptor == nullptr)
  413. {
  414. DISCOVERY_OUT("error", "DSSI plugin doesn't provide the LADSPA interface");
  415. return;
  416. }
  417. if (doInit && ldescriptor->instantiate != nullptr && ldescriptor->cleanup != nullptr)
  418. {
  419. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  420. if (handle == nullptr)
  421. {
  422. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  423. return;
  424. }
  425. ldescriptor->cleanup(handle);
  426. lib_close(libHandle);
  427. libHandle = lib_open(filename);
  428. if (libHandle == nullptr)
  429. {
  430. print_lib_error(filename);
  431. return;
  432. }
  433. descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  434. if (descFn == nullptr)
  435. {
  436. DISCOVERY_OUT("error", "Not a DSSI plugin (#2)");
  437. return;
  438. }
  439. }
  440. }
  441. unsigned long i = 0;
  442. while ((descriptor = descFn(i++)) != nullptr)
  443. {
  444. const LADSPA_Descriptor* const ldescriptor = descriptor->LADSPA_Plugin;
  445. if (ldescriptor == nullptr)
  446. {
  447. DISCOVERY_OUT("error", "Plugin has no LADSPA interface");
  448. continue;
  449. }
  450. if (descriptor->DSSI_API_Version != DSSI_VERSION_MAJOR)
  451. {
  452. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' uses an unsupported DSSI spec version " << descriptor->DSSI_API_Version);
  453. continue;
  454. }
  455. if (ldescriptor->instantiate == nullptr)
  456. {
  457. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no instantiate()");
  458. continue;
  459. }
  460. if (ldescriptor->cleanup == nullptr)
  461. {
  462. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no cleanup()");
  463. continue;
  464. }
  465. if (ldescriptor->run == nullptr && descriptor->run_synth == nullptr)
  466. {
  467. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no run() or run_synth()");
  468. continue;
  469. }
  470. if (descriptor->run_synth == nullptr && descriptor->run_multiple_synths != nullptr)
  471. {
  472. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' requires run_multiple_synths which is not supported");
  473. continue;
  474. }
  475. if (! LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  476. {
  477. DISCOVERY_OUT("warning", "Plugin '" << ldescriptor->Name << "' is not hard real-time capable");
  478. }
  479. uint hints = 0x0;
  480. uint audioIns = 0;
  481. uint audioOuts = 0;
  482. uint midiIns = 0;
  483. uint parametersIns = 0;
  484. uint parametersOuts = 0;
  485. uint parametersTotal = 0;
  486. if (LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  487. hints |= PLUGIN_IS_RTSAFE;
  488. for (unsigned long j=0; j < ldescriptor->PortCount; ++j)
  489. {
  490. CARLA_ASSERT(ldescriptor->PortNames[j] != nullptr);
  491. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  492. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  493. {
  494. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  495. audioIns += 1;
  496. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  497. audioOuts += 1;
  498. }
  499. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  500. {
  501. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  502. parametersIns += 1;
  503. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(ldescriptor->PortNames[j], "latency") != 0 && std::strcmp(ldescriptor->PortNames[j], "_latency") != 0)
  504. parametersOuts += 1;
  505. parametersTotal += 1;
  506. }
  507. }
  508. CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
  509. CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
  510. if (descriptor->run_synth != nullptr)
  511. midiIns = 1;
  512. if (midiIns > 0 && audioIns == 0 && audioOuts > 0)
  513. hints |= PLUGIN_IS_SYNTH;
  514. #ifndef BUILD_BRIDGE
  515. if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label))
  516. {
  517. hints |= PLUGIN_HAS_CUSTOM_UI;
  518. delete[] ui;
  519. }
  520. #endif
  521. if (doInit)
  522. {
  523. // -----------------------------------------------------------------------
  524. // start crash-free plugin test
  525. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  526. if (handle == nullptr)
  527. {
  528. DISCOVERY_OUT("error", "Failed to init DSSI plugin");
  529. continue;
  530. }
  531. // Test quick init and cleanup
  532. ldescriptor->cleanup(handle);
  533. handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  534. if (handle == nullptr)
  535. {
  536. DISCOVERY_OUT("error", "Failed to init DSSI plugin (#2)");
  537. continue;
  538. }
  539. LADSPA_Data* bufferParams = new LADSPA_Data[parametersTotal];
  540. LADSPA_Data bufferAudio[kBufferSize][MAX_DISCOVERY_AUDIO_IO];
  541. LADSPA_Data min, max, def;
  542. for (unsigned long j=0, iA=0, iC=0; j < ldescriptor->PortCount; ++j)
  543. {
  544. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  545. const LADSPA_PortRangeHint portRangeHints = ldescriptor->PortRangeHints[j];
  546. const char* const portName = ldescriptor->PortNames[j];
  547. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  548. {
  549. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  550. ldescriptor->connect_port(handle, j, bufferAudio[iA++]);
  551. }
  552. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  553. {
  554. // min value
  555. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  556. min = portRangeHints.LowerBound;
  557. else
  558. min = 0.0f;
  559. // max value
  560. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  561. max = portRangeHints.UpperBound;
  562. else
  563. max = 1.0f;
  564. if (min > max)
  565. {
  566. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  567. max = min + 0.1f;
  568. }
  569. else if (carla_isEqual(min, max))
  570. {
  571. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  572. max = min + 0.1f;
  573. }
  574. // default value
  575. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  576. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  577. {
  578. min *= kSampleRatef;
  579. max *= kSampleRatef;
  580. def *= kSampleRatef;
  581. }
  582. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  583. {
  584. // latency parameter
  585. def = 0.0f;
  586. }
  587. else
  588. {
  589. if (def < min)
  590. def = min;
  591. else if (def > max)
  592. def = max;
  593. }
  594. bufferParams[iC] = def;
  595. ldescriptor->connect_port(handle, j, &bufferParams[iC++]);
  596. }
  597. }
  598. // select first midi-program if available
  599. if (descriptor->get_program != nullptr && descriptor->select_program != nullptr)
  600. {
  601. if (const DSSI_Program_Descriptor* const pDesc = descriptor->get_program(handle, 0))
  602. descriptor->select_program(handle, pDesc->Bank, pDesc->Program);
  603. }
  604. if (ldescriptor->activate != nullptr)
  605. ldescriptor->activate(handle);
  606. if (descriptor->run_synth != nullptr)
  607. {
  608. snd_seq_event_t midiEvents[2];
  609. carla_zeroStructs(midiEvents, 2);
  610. const unsigned long midiEventCount = 2;
  611. midiEvents[0].type = SND_SEQ_EVENT_NOTEON;
  612. midiEvents[0].data.note.note = 64;
  613. midiEvents[0].data.note.velocity = 100;
  614. midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF;
  615. midiEvents[1].data.note.note = 64;
  616. midiEvents[1].data.note.velocity = 0;
  617. midiEvents[1].time.tick = kBufferSize/2;
  618. descriptor->run_synth(handle, kBufferSize, midiEvents, midiEventCount);
  619. }
  620. else
  621. ldescriptor->run(handle, kBufferSize);
  622. if (ldescriptor->deactivate != nullptr)
  623. ldescriptor->deactivate(handle);
  624. ldescriptor->cleanup(handle);
  625. delete[] bufferParams;
  626. // end crash-free plugin test
  627. // -----------------------------------------------------------------------
  628. }
  629. DISCOVERY_OUT("init", "------------");
  630. DISCOVERY_OUT("build", BINARY_NATIVE);
  631. DISCOVERY_OUT("category", ((hints & PLUGIN_IS_SYNTH)
  632. ? "synth"
  633. : getPluginCategoryAsString(getPluginCategoryFromName(ldescriptor->Name))));
  634. DISCOVERY_OUT("hints", hints);
  635. DISCOVERY_OUT("name", ldescriptor->Name);
  636. DISCOVERY_OUT("label", ldescriptor->Label);
  637. DISCOVERY_OUT("maker", ldescriptor->Maker);
  638. DISCOVERY_OUT("uniqueId", ldescriptor->UniqueID);
  639. DISCOVERY_OUT("audio.ins", audioIns);
  640. DISCOVERY_OUT("audio.outs", audioOuts);
  641. DISCOVERY_OUT("midi.ins", midiIns);
  642. DISCOVERY_OUT("parameters.ins", parametersIns);
  643. DISCOVERY_OUT("parameters.outs", parametersOuts);
  644. DISCOVERY_OUT("end", "------------");
  645. }
  646. }
  647. // --------------------------------------------------------------------------------------------------------------------
  648. // LV2
  649. #ifndef BUILD_BRIDGE
  650. static void do_lv2_check(const char* const bundle, const bool doInit)
  651. {
  652. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  653. Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, bundle));
  654. CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(),);
  655. CarlaString sBundle(bundleNode.as_uri());
  656. if (! sBundle.endsWith("/"))
  657. sBundle += "/";
  658. // Load bundle
  659. lv2World.load_bundle(sBundle);
  660. // Load plugins in this bundle
  661. const Lilv::Plugins lilvPlugins(lv2World.get_all_plugins());
  662. // Get all plugin URIs in this bundle
  663. CarlaStringList URIs;
  664. LILV_FOREACH(plugins, it, lilvPlugins)
  665. {
  666. Lilv::Plugin lilvPlugin(lilv_plugins_get(lilvPlugins, it));
  667. if (const char* const uri = lilvPlugin.get_uri().as_string())
  668. URIs.appendUnique(uri);
  669. }
  670. if (URIs.isEmpty())
  671. {
  672. DISCOVERY_OUT("warning", "LV2 Bundle doesn't provide any plugins");
  673. return;
  674. }
  675. // Get & check every plugin-instance
  676. for (CarlaStringList::Itenerator it=URIs.begin2(); it.valid(); it.next())
  677. {
  678. const char* const URI = it.getValue(nullptr);
  679. CARLA_SAFE_ASSERT_CONTINUE(URI != nullptr);
  680. CarlaScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));
  681. if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr)
  682. {
  683. DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'");
  684. continue;
  685. }
  686. if (doInit)
  687. {
  688. // test if lib is loadable, twice
  689. const lib_t libHandle1 = lib_open(rdfDescriptor->Binary);
  690. if (libHandle1 == nullptr)
  691. {
  692. print_lib_error(rdfDescriptor->Binary);
  693. delete rdfDescriptor;
  694. continue;
  695. }
  696. lib_close(libHandle1);
  697. const lib_t libHandle2 = lib_open(rdfDescriptor->Binary);
  698. if (libHandle2 == nullptr)
  699. {
  700. print_lib_error(rdfDescriptor->Binary);
  701. delete rdfDescriptor;
  702. continue;
  703. }
  704. lib_close(libHandle2);
  705. }
  706. const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI));
  707. CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr);
  708. Lilv::Plugin lilvPlugin(cPlugin);
  709. CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri());
  710. print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin));
  711. }
  712. }
  713. #endif // ! BUILD_BRIDGE
  714. // --------------------------------------------------------------------------------------------------------------------
  715. // VST2
  716. // Check if plugin is currently processing
  717. static bool gVstIsProcessing = false;
  718. // Check if plugin needs idle
  719. static bool gVstNeedsIdle = false;
  720. // Check if plugin wants midi
  721. static bool gVstWantsMidi = false;
  722. // Check if plugin wants time
  723. static bool gVstWantsTime = false;
  724. // Current uniqueId for VST shell plugins
  725. static intptr_t gVstCurrentUniqueId = 0;
  726. // Supported Carla features
  727. static intptr_t vstHostCanDo(const char* const feature)
  728. {
  729. carla_debug("vstHostCanDo(\"%s\")", feature);
  730. if (std::strcmp(feature, "supplyIdle") == 0)
  731. return 1;
  732. if (std::strcmp(feature, "sendVstEvents") == 0)
  733. return 1;
  734. if (std::strcmp(feature, "sendVstMidiEvent") == 0)
  735. return 1;
  736. if (std::strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
  737. return 1;
  738. if (std::strcmp(feature, "sendVstTimeInfo") == 0)
  739. {
  740. gVstWantsTime = true;
  741. return 1;
  742. }
  743. if (std::strcmp(feature, "receiveVstEvents") == 0)
  744. return 1;
  745. if (std::strcmp(feature, "receiveVstMidiEvent") == 0)
  746. return 1;
  747. if (std::strcmp(feature, "receiveVstTimeInfo") == 0)
  748. return -1;
  749. if (std::strcmp(feature, "reportConnectionChanges") == 0)
  750. return -1;
  751. if (std::strcmp(feature, "acceptIOChanges") == 0)
  752. return 1;
  753. if (std::strcmp(feature, "sizeWindow") == 0)
  754. return 1;
  755. if (std::strcmp(feature, "offline") == 0)
  756. return -1;
  757. if (std::strcmp(feature, "openFileSelector") == 0)
  758. return -1;
  759. if (std::strcmp(feature, "closeFileSelector") == 0)
  760. return -1;
  761. if (std::strcmp(feature, "startStopProcess") == 0)
  762. return 1;
  763. if (std::strcmp(feature, "supportShell") == 0)
  764. return 1;
  765. if (std::strcmp(feature, "shellCategory") == 0)
  766. return 1;
  767. if (std::strcmp(feature, "NIMKPIVendorSpecificCallbacks") == 0)
  768. return -1;
  769. // non-official features found in some plugins:
  770. // "asyncProcessing"
  771. // "editFile"
  772. // unimplemented
  773. carla_stderr("vstHostCanDo(\"%s\") - unknown feature", feature);
  774. return 0;
  775. }
  776. // Host-side callback
  777. 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)
  778. {
  779. carla_debug("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
  780. effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
  781. static VstTimeInfo timeInfo;
  782. intptr_t ret = 0;
  783. switch (opcode)
  784. {
  785. case audioMasterAutomate:
  786. ret = 1;
  787. break;
  788. case audioMasterVersion:
  789. ret = kVstVersion;
  790. break;
  791. case audioMasterCurrentId:
  792. ret = gVstCurrentUniqueId;
  793. break;
  794. case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
  795. if (gVstWantsMidi) { DISCOVERY_OUT("warning", "Plugin requested MIDI more than once"); }
  796. gVstWantsMidi = true;
  797. ret = 1;
  798. break;
  799. case audioMasterGetTime:
  800. if (! gVstIsProcessing) { DISCOVERY_OUT("warning", "Plugin requested timeInfo out of process"); }
  801. if (! gVstWantsTime) { DISCOVERY_OUT("warning", "Plugin requested timeInfo but didn't ask if host could do \"sendVstTimeInfo\""); }
  802. carla_zeroStruct(timeInfo);
  803. timeInfo.sampleRate = kSampleRate;
  804. // Tempo
  805. timeInfo.tempo = 120.0;
  806. timeInfo.flags |= kVstTempoValid;
  807. // Time Signature
  808. timeInfo.timeSigNumerator = 4;
  809. timeInfo.timeSigDenominator = 4;
  810. timeInfo.flags |= kVstTimeSigValid;
  811. ret = (intptr_t)&timeInfo;
  812. break;
  813. case DECLARE_VST_DEPRECATED(audioMasterTempoAt):
  814. ret = 120 * 10000;
  815. break;
  816. case DECLARE_VST_DEPRECATED(audioMasterGetNumAutomatableParameters):
  817. ret = carla_minPositive(effect->numParams, static_cast<int>(MAX_DEFAULT_PARAMETERS));
  818. break;
  819. case DECLARE_VST_DEPRECATED(audioMasterGetParameterQuantization):
  820. ret = 1; // full single float precision
  821. break;
  822. case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
  823. if (gVstNeedsIdle) { DISCOVERY_OUT("warning", "Plugin requested idle more than once"); }
  824. gVstNeedsIdle = true;
  825. ret = 1;
  826. break;
  827. case audioMasterGetSampleRate:
  828. ret = kSampleRatei;
  829. break;
  830. case audioMasterGetBlockSize:
  831. ret = kBufferSize;
  832. break;
  833. case DECLARE_VST_DEPRECATED(audioMasterWillReplaceOrAccumulate):
  834. ret = 1; // replace
  835. break;
  836. case audioMasterGetCurrentProcessLevel:
  837. ret = gVstIsProcessing ? kVstProcessLevelRealtime : kVstProcessLevelUser;
  838. break;
  839. case audioMasterGetAutomationState:
  840. ret = kVstAutomationOff;
  841. break;
  842. case audioMasterGetVendorString:
  843. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  844. std::strcpy((char*)ptr, "falkTX");
  845. ret = 1;
  846. break;
  847. case audioMasterGetProductString:
  848. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  849. std::strcpy((char*)ptr, "Carla-Discovery");
  850. ret = 1;
  851. break;
  852. case audioMasterGetVendorVersion:
  853. ret = CARLA_VERSION_HEX;
  854. break;
  855. case audioMasterCanDo:
  856. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  857. ret = vstHostCanDo((const char*)ptr);
  858. break;
  859. case audioMasterGetLanguage:
  860. ret = kVstLangEnglish;
  861. break;
  862. default:
  863. carla_stdout("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
  864. effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
  865. break;
  866. }
  867. return ret;
  868. }
  869. static bool do_vst2_check(lib_t& libHandle, const char* const filename, const bool doInit)
  870. {
  871. VST_Function vstFn = nullptr;
  872. #ifdef CARLA_OS_MAC
  873. BundleLoader bundleLoader;
  874. if (libHandle == nullptr)
  875. {
  876. if (! bundleLoader.load(filename))
  877. {
  878. #ifdef __aarch64__
  879. return true;
  880. #else
  881. DISCOVERY_OUT("error", "Failed to load VST2 bundle executable");
  882. return false;
  883. #endif
  884. }
  885. vstFn = bundleLoader.getSymbol<VST_Function>(CFSTR("main_macho"));
  886. if (vstFn == nullptr)
  887. vstFn = bundleLoader.getSymbol<VST_Function>(CFSTR("VSTPluginMain"));
  888. if (vstFn == nullptr)
  889. {
  890. DISCOVERY_OUT("error", "Not a VST2 plugin");
  891. return false;
  892. }
  893. }
  894. else
  895. #endif
  896. {
  897. vstFn = lib_symbol<VST_Function>(libHandle, "VSTPluginMain");
  898. if (vstFn == nullptr)
  899. {
  900. vstFn = lib_symbol<VST_Function>(libHandle, "main");
  901. if (vstFn == nullptr)
  902. {
  903. DISCOVERY_OUT("error", "Not a VST plugin");
  904. return false;
  905. }
  906. }
  907. }
  908. AEffect* effect = vstFn(vstHostCallback);
  909. if (effect == nullptr || effect->magic != kEffectMagic)
  910. {
  911. DISCOVERY_OUT("error", "Failed to init VST plugin, or VST magic failed");
  912. return false;
  913. }
  914. if (effect->uniqueID == 0)
  915. {
  916. DISCOVERY_OUT("warning", "Plugin doesn't have an Unique ID when first loaded");
  917. }
  918. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  919. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  920. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  921. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  922. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  923. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  924. if (effect->numPrograms > 0)
  925. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  926. const bool isShell = (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f) == kPlugCategShell);
  927. if (effect->uniqueID == 0 && !isShell)
  928. {
  929. DISCOVERY_OUT("error", "Plugin doesn't have an Unique ID after being open");
  930. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  931. return false;
  932. }
  933. gVstCurrentUniqueId = effect->uniqueID;
  934. char strBuf[STR_MAX+1];
  935. CarlaString cName;
  936. CarlaString cProduct;
  937. CarlaString cVendor;
  938. PluginCategory category;
  939. LinkedList<intptr_t> uniqueIds;
  940. if (isShell)
  941. {
  942. for (;;)
  943. {
  944. carla_zeroChars(strBuf, STR_MAX+1);
  945. gVstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, strBuf, 0.0f);
  946. if (gVstCurrentUniqueId == 0)
  947. break;
  948. uniqueIds.append(gVstCurrentUniqueId);
  949. }
  950. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  951. effect = nullptr;
  952. }
  953. else
  954. {
  955. uniqueIds.append(gVstCurrentUniqueId);
  956. }
  957. for (LinkedList<intptr_t>::Itenerator it = uniqueIds.begin2(); it.valid(); it.next())
  958. {
  959. gVstCurrentUniqueId = it.getValue(0);
  960. if (effect == nullptr)
  961. {
  962. effect = vstFn(vstHostCallback);
  963. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  964. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  965. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  966. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  967. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  968. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  969. if (effect->numPrograms > 0)
  970. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  971. }
  972. // get name
  973. carla_zeroChars(strBuf, STR_MAX+1);
  974. if (effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f) == 1)
  975. cName = strBuf;
  976. else
  977. cName.clear();
  978. // get product
  979. carla_zeroChars(strBuf, STR_MAX+1);
  980. if (effect->dispatcher(effect, effGetProductString, 0, 0, strBuf, 0.0f) == 1)
  981. cProduct = strBuf;
  982. else
  983. cProduct.clear();
  984. // get vendor
  985. carla_zeroChars(strBuf, STR_MAX+1);
  986. if (effect->dispatcher(effect, effGetVendorString, 0, 0, strBuf, 0.0f) == 1)
  987. cVendor = strBuf;
  988. else
  989. cVendor.clear();
  990. // get category
  991. switch (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f))
  992. {
  993. case kPlugCategSynth:
  994. category = PLUGIN_CATEGORY_SYNTH;
  995. break;
  996. case kPlugCategAnalysis:
  997. category = PLUGIN_CATEGORY_UTILITY;
  998. break;
  999. case kPlugCategMastering:
  1000. category = PLUGIN_CATEGORY_DYNAMICS;
  1001. break;
  1002. case kPlugCategRoomFx:
  1003. category = PLUGIN_CATEGORY_DELAY;
  1004. break;
  1005. case kPlugCategRestoration:
  1006. category = PLUGIN_CATEGORY_UTILITY;
  1007. break;
  1008. case kPlugCategGenerator:
  1009. category = PLUGIN_CATEGORY_SYNTH;
  1010. break;
  1011. default:
  1012. if (effect->flags & effFlagsIsSynth)
  1013. category = PLUGIN_CATEGORY_SYNTH;
  1014. else
  1015. category = PLUGIN_CATEGORY_NONE;
  1016. break;
  1017. }
  1018. // get everything else
  1019. uint hints = 0x0;
  1020. uint audioIns = static_cast<uint>(std::max(0, effect->numInputs));
  1021. uint audioOuts = static_cast<uint>(std::max(0, effect->numOutputs));
  1022. uint midiIns = 0;
  1023. uint midiOuts = 0;
  1024. uint parameters = static_cast<uint>(std::max(0, effect->numParams));
  1025. if (effect->flags & effFlagsHasEditor)
  1026. {
  1027. hints |= PLUGIN_HAS_CUSTOM_UI;
  1028. #ifndef BUILD_BRIDGE
  1029. hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  1030. #endif
  1031. }
  1032. if (effect->flags & effFlagsIsSynth)
  1033. {
  1034. hints |= PLUGIN_IS_SYNTH;
  1035. midiIns = 1;
  1036. }
  1037. if (vstPluginCanDo(effect, "receiveVstEvents") || vstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) != 0)
  1038. midiIns = 1;
  1039. if (vstPluginCanDo(effect, "sendVstEvents") || vstPluginCanDo(effect, "sendVstMidiEvent"))
  1040. midiOuts = 1;
  1041. CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
  1042. CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
  1043. // -----------------------------------------------------------------------
  1044. // start crash-free plugin test
  1045. if (doInit)
  1046. {
  1047. if (gVstNeedsIdle)
  1048. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1049. effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f);
  1050. effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f);
  1051. if (gVstNeedsIdle)
  1052. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1053. // Plugin might call wantMidi() during resume
  1054. if (midiIns == 0 && gVstWantsMidi)
  1055. {
  1056. midiIns = 1;
  1057. }
  1058. float* bufferAudioIn[MAX_DISCOVERY_AUDIO_IO];
  1059. float* bufferAudioOut[MAX_DISCOVERY_AUDIO_IO];
  1060. if (audioIns == 0)
  1061. {
  1062. bufferAudioIn[0] = nullptr;
  1063. }
  1064. else
  1065. {
  1066. for (uint j=0; j < audioIns; ++j)
  1067. {
  1068. bufferAudioIn[j] = new float[kBufferSize];
  1069. carla_zeroFloats(bufferAudioIn[j], kBufferSize);
  1070. }
  1071. }
  1072. if (audioOuts == 0)
  1073. {
  1074. bufferAudioOut[0] = nullptr;
  1075. }
  1076. else
  1077. {
  1078. for (uint j=0; j < audioOuts; ++j)
  1079. {
  1080. bufferAudioOut[j] = new float[kBufferSize];
  1081. carla_zeroFloats(bufferAudioOut[j], kBufferSize);
  1082. }
  1083. }
  1084. struct VstEventsFixed {
  1085. int32_t numEvents;
  1086. intptr_t reserved;
  1087. VstEvent* data[2];
  1088. VstEventsFixed()
  1089. : numEvents(0),
  1090. reserved(0)
  1091. {
  1092. data[0] = data[1] = nullptr;
  1093. }
  1094. } events;
  1095. VstMidiEvent midiEvents[2];
  1096. carla_zeroStructs(midiEvents, 2);
  1097. midiEvents[0].type = kVstMidiType;
  1098. midiEvents[0].byteSize = sizeof(VstMidiEvent);
  1099. midiEvents[0].midiData[0] = char(MIDI_STATUS_NOTE_ON);
  1100. midiEvents[0].midiData[1] = 64;
  1101. midiEvents[0].midiData[2] = 100;
  1102. midiEvents[1].type = kVstMidiType;
  1103. midiEvents[1].byteSize = sizeof(VstMidiEvent);
  1104. midiEvents[1].midiData[0] = char(MIDI_STATUS_NOTE_OFF);
  1105. midiEvents[1].midiData[1] = 64;
  1106. midiEvents[1].deltaFrames = kBufferSize/2;
  1107. events.numEvents = 2;
  1108. events.data[0] = (VstEvent*)&midiEvents[0];
  1109. events.data[1] = (VstEvent*)&midiEvents[1];
  1110. // processing
  1111. gVstIsProcessing = true;
  1112. if (midiIns > 0)
  1113. effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f);
  1114. if ((effect->flags & effFlagsCanReplacing) > 0 && effect->processReplacing != nullptr && effect->processReplacing != effect->DECLARE_VST_DEPRECATED(process))
  1115. effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  1116. else if (effect->DECLARE_VST_DEPRECATED(process) != nullptr)
  1117. effect->DECLARE_VST_DEPRECATED(process)(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  1118. else
  1119. DISCOVERY_OUT("error", "Plugin doesn't have a process function");
  1120. gVstIsProcessing = false;
  1121. effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f);
  1122. effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
  1123. if (gVstNeedsIdle)
  1124. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1125. for (uint j=0; j < audioIns; ++j)
  1126. delete[] bufferAudioIn[j];
  1127. for (uint j=0; j < audioOuts; ++j)
  1128. delete[] bufferAudioOut[j];
  1129. }
  1130. // end crash-free plugin test
  1131. // -----------------------------------------------------------------------
  1132. DISCOVERY_OUT("init", "------------");
  1133. DISCOVERY_OUT("build", BINARY_NATIVE);
  1134. DISCOVERY_OUT("hints", hints);
  1135. DISCOVERY_OUT("category", getPluginCategoryAsString(category));
  1136. DISCOVERY_OUT("name", cName.buffer());
  1137. DISCOVERY_OUT("label", cProduct.buffer());
  1138. DISCOVERY_OUT("maker", cVendor.buffer());
  1139. DISCOVERY_OUT("uniqueId", gVstCurrentUniqueId);
  1140. DISCOVERY_OUT("audio.ins", audioIns);
  1141. DISCOVERY_OUT("audio.outs", audioOuts);
  1142. DISCOVERY_OUT("midi.ins", midiIns);
  1143. DISCOVERY_OUT("midi.outs", midiOuts);
  1144. DISCOVERY_OUT("parameters.ins", parameters);
  1145. DISCOVERY_OUT("end", "------------");
  1146. gVstWantsMidi = false;
  1147. gVstWantsTime = false;
  1148. if (! isShell)
  1149. break;
  1150. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1151. effect = nullptr;
  1152. }
  1153. uniqueIds.clear();
  1154. if (effect != nullptr)
  1155. {
  1156. if (gVstNeedsIdle)
  1157. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1158. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1159. }
  1160. return false;
  1161. #ifndef CARLA_OS_MAC
  1162. // unused
  1163. (void)filename;
  1164. #endif
  1165. }
  1166. // --------------------------------------------------------------------------------------------------------------------
  1167. // VST3
  1168. struct carla_v3_host_application : v3_host_application_cpp {
  1169. carla_v3_host_application()
  1170. {
  1171. query_interface = v3_query_interface_static<v3_host_application_iid>;
  1172. ref = v3_ref_static;
  1173. unref = v3_unref_static;
  1174. app.get_name = carla_get_name;
  1175. app.create_instance = carla_create_instance;
  1176. }
  1177. private:
  1178. static v3_result V3_API carla_get_name(void*, v3_str_128 name)
  1179. {
  1180. static constexpr const char hostname[] = "Carla-Discovery\0";
  1181. for (size_t i=0; i<sizeof(hostname); ++i)
  1182. name[i] = hostname[i];
  1183. return V3_OK;
  1184. }
  1185. static v3_result V3_API carla_create_instance(void*, v3_tuid, v3_tuid, void**)
  1186. {
  1187. return V3_NOT_IMPLEMENTED;
  1188. }
  1189. CARLA_DECLARE_NON_COPYABLE(carla_v3_host_application)
  1190. CARLA_PREVENT_HEAP_ALLOCATION
  1191. };
  1192. struct carla_v3_param_value_queue : v3_param_value_queue_cpp {
  1193. carla_v3_param_value_queue()
  1194. {
  1195. query_interface = v3_query_interface_static<v3_param_value_queue_iid>;
  1196. ref = v3_ref_static;
  1197. unref = v3_unref_static;
  1198. queue.get_param_id = carla_get_param_id;
  1199. queue.get_point_count = carla_get_point_count;
  1200. queue.get_point = carla_get_point;
  1201. queue.add_point = carla_add_point;
  1202. }
  1203. private:
  1204. static v3_param_id V3_API carla_get_param_id(void*) { return 0; }
  1205. static int32_t V3_API carla_get_point_count(void*) { return 0; }
  1206. static v3_result V3_API carla_get_point(void*, int32_t, int32_t*, double*) { return V3_NOT_IMPLEMENTED; }
  1207. static v3_result V3_API carla_add_point(void*, int32_t, double, int32_t*) { return V3_NOT_IMPLEMENTED; }
  1208. CARLA_DECLARE_NON_COPYABLE(carla_v3_param_value_queue)
  1209. CARLA_PREVENT_HEAP_ALLOCATION
  1210. };
  1211. struct carla_v3_param_changes : v3_param_changes_cpp {
  1212. carla_v3_param_changes()
  1213. {
  1214. query_interface = v3_query_interface_static<v3_param_changes_iid>;
  1215. ref = v3_ref_static;
  1216. unref = v3_unref_static;
  1217. changes.get_param_count = carla_get_param_count;
  1218. changes.get_param_data = carla_get_param_data;
  1219. changes.add_param_data = carla_add_param_data;
  1220. }
  1221. private:
  1222. static int32_t V3_API carla_get_param_count(void*) { return 0; }
  1223. static v3_param_value_queue** V3_API carla_get_param_data(void*, int32_t) { return nullptr; }
  1224. static v3_param_value_queue** V3_API carla_add_param_data(void*, const v3_param_id*, int32_t*) { return nullptr; }
  1225. CARLA_DECLARE_NON_COPYABLE(carla_v3_param_changes)
  1226. CARLA_PREVENT_HEAP_ALLOCATION
  1227. };
  1228. struct carla_v3_event_list : v3_event_list_cpp {
  1229. carla_v3_event_list()
  1230. {
  1231. query_interface = v3_query_interface_static<v3_event_list_iid>;
  1232. ref = v3_ref_static;
  1233. unref = v3_unref_static;
  1234. list.get_event_count = carla_get_event_count;
  1235. list.get_event = carla_get_event;
  1236. list.add_event = carla_add_event;
  1237. }
  1238. private:
  1239. static uint32_t V3_API carla_get_event_count(void*) { return 0; }
  1240. static v3_result V3_API carla_get_event(void*, int32_t, v3_event*) { return V3_NOT_IMPLEMENTED; }
  1241. static v3_result V3_API carla_add_event(void*, v3_event*) { return V3_NOT_IMPLEMENTED; }
  1242. CARLA_DECLARE_NON_COPYABLE(carla_v3_event_list)
  1243. CARLA_PREVENT_HEAP_ALLOCATION
  1244. };
  1245. static bool v3_exit_false(const V3_EXITFN v3_exit)
  1246. {
  1247. v3_exit();
  1248. return false;
  1249. }
  1250. static bool do_vst3_check(lib_t& libHandle, const char* const filename, const bool doInit)
  1251. {
  1252. V3_ENTRYFN v3_entry = nullptr;
  1253. V3_EXITFN v3_exit = nullptr;
  1254. V3_GETFN v3_get = nullptr;
  1255. #ifdef CARLA_OS_MAC
  1256. BundleLoader bundleLoader;
  1257. #endif
  1258. // if passed filename is not a plugin binary directly, inspect bundle and find one
  1259. if (libHandle == nullptr)
  1260. {
  1261. #ifdef CARLA_OS_MAC
  1262. if (! bundleLoader.load(filename))
  1263. {
  1264. #ifdef __aarch64__
  1265. return true;
  1266. #else
  1267. DISCOVERY_OUT("error", "Failed to load VST3 bundle executable");
  1268. return false;
  1269. #endif
  1270. }
  1271. v3_entry = bundleLoader.getSymbol<V3_ENTRYFN>(CFSTR(V3_ENTRYFNNAME));
  1272. v3_exit = bundleLoader.getSymbol<V3_EXITFN>(CFSTR(V3_EXITFNNAME));
  1273. v3_get = bundleLoader.getSymbol<V3_GETFN>(CFSTR(V3_GETFNNAME));
  1274. #else
  1275. water::String binaryfilename = filename;
  1276. if (!binaryfilename.endsWithChar(CARLA_OS_SEP))
  1277. binaryfilename += CARLA_OS_SEP_STR;
  1278. binaryfilename += "Contents" CARLA_OS_SEP_STR V3_CONTENT_DIR CARLA_OS_SEP_STR;
  1279. binaryfilename += water::File(filename).getFileNameWithoutExtension();
  1280. #ifdef CARLA_OS_WIN
  1281. binaryfilename += ".vst3";
  1282. #else
  1283. binaryfilename += ".so";
  1284. #endif
  1285. if (! water::File(binaryfilename.toRawUTF8()).existsAsFile())
  1286. {
  1287. DISCOVERY_OUT("error", "Failed to find a suitable VST3 bundle binary");
  1288. return false;
  1289. }
  1290. libHandle = lib_open(binaryfilename.toRawUTF8());
  1291. if (libHandle == nullptr)
  1292. {
  1293. print_lib_error(filename);
  1294. return false;
  1295. }
  1296. #endif
  1297. }
  1298. #ifndef CARLA_OS_MAC
  1299. v3_entry = lib_symbol<V3_ENTRYFN>(libHandle, V3_ENTRYFNNAME);
  1300. v3_exit = lib_symbol<V3_EXITFN>(libHandle, V3_EXITFNNAME);
  1301. v3_get = lib_symbol<V3_GETFN>(libHandle, V3_GETFNNAME);
  1302. #endif
  1303. // ensure entry and exit points are available
  1304. if (v3_entry == nullptr || v3_exit == nullptr || v3_get == nullptr)
  1305. {
  1306. DISCOVERY_OUT("error", "Not a VST3 plugin");
  1307. return false;
  1308. }
  1309. // call entry point
  1310. #if defined(CARLA_OS_MAC)
  1311. v3_entry(bundleLoader.getRef());
  1312. #elif defined(CARLA_OS_WIN)
  1313. v3_entry();
  1314. #else
  1315. v3_entry(libHandle);
  1316. #endif
  1317. carla_v3_host_application hostApplication;
  1318. carla_v3_host_application* hostApplicationPtr = &hostApplication;
  1319. v3_funknown** const hostContext = (v3_funknown**)&hostApplicationPtr;
  1320. // fetch initial factory
  1321. v3_plugin_factory** factory1 = v3_get();
  1322. CARLA_SAFE_ASSERT_RETURN(factory1 != nullptr, v3_exit_false(v3_exit));
  1323. // get factory info
  1324. v3_factory_info factoryInfo = {};
  1325. CARLA_SAFE_ASSERT_RETURN(v3_cpp_obj(factory1)->get_factory_info(factory1, &factoryInfo) == V3_OK,
  1326. v3_exit_false(v3_exit));
  1327. // get num classes
  1328. const int32_t numClasses = v3_cpp_obj(factory1)->num_classes(factory1);
  1329. CARLA_SAFE_ASSERT_RETURN(numClasses > 0, v3_exit_false(v3_exit));
  1330. // query 2nd factory
  1331. v3_plugin_factory_2** factory2 = nullptr;
  1332. if (v3_cpp_obj_query_interface(factory1, v3_plugin_factory_2_iid, &factory2) == V3_OK)
  1333. {
  1334. CARLA_SAFE_ASSERT_RETURN(factory2 != nullptr, v3_exit_false(v3_exit));
  1335. }
  1336. else
  1337. {
  1338. CARLA_SAFE_ASSERT(factory2 == nullptr);
  1339. factory2 = nullptr;
  1340. }
  1341. // query 3rd factory
  1342. v3_plugin_factory_3** factory3 = nullptr;
  1343. if (factory2 != nullptr && v3_cpp_obj_query_interface(factory2, v3_plugin_factory_3_iid, &factory3) == V3_OK)
  1344. {
  1345. CARLA_SAFE_ASSERT_RETURN(factory3 != nullptr, v3_exit_false(v3_exit));
  1346. }
  1347. else
  1348. {
  1349. CARLA_SAFE_ASSERT(factory3 == nullptr);
  1350. factory3 = nullptr;
  1351. }
  1352. // set host context (application) if 3rd factory provided
  1353. if (factory3 != nullptr)
  1354. v3_cpp_obj(factory3)->set_host_context(factory3, hostContext);
  1355. // go through all relevant classes
  1356. for (int32_t i=0; i<numClasses; ++i)
  1357. {
  1358. v3_result res;
  1359. // v3_class_info_2 is ABI compatible with v3_class_info
  1360. union {
  1361. v3_class_info v1;
  1362. v3_class_info_2 v2;
  1363. } classInfo = {};
  1364. if (factory2 != nullptr)
  1365. v3_cpp_obj(factory2)->get_class_info_2(factory2, i, &classInfo.v2);
  1366. else
  1367. v3_cpp_obj(factory1)->get_class_info(factory1, i, &classInfo.v1);
  1368. // safety check
  1369. CARLA_SAFE_ASSERT_CONTINUE(classInfo.v1.cardinality == 0x7FFFFFFF);
  1370. // only check for audio plugins
  1371. if (std::strcmp(classInfo.v1.category, "Audio Module Class") != 0)
  1372. continue;
  1373. // create instance
  1374. void* instance = nullptr;
  1375. res = v3_cpp_obj(factory1)->create_instance(factory1, classInfo.v1.class_id, v3_component_iid, &instance);
  1376. CARLA_SAFE_ASSERT_INT_CONTINUE(res == V3_OK, res);
  1377. CARLA_SAFE_ASSERT_CONTINUE(instance != nullptr);
  1378. // initialize instance
  1379. v3_component** const component = static_cast<v3_component**>(instance);
  1380. res = v3_cpp_obj_initialize(component, hostContext);
  1381. CARLA_SAFE_ASSERT_INT_CONTINUE(res == V3_OK, res);
  1382. // create edit controller
  1383. v3_edit_controller** controller = nullptr;
  1384. bool shouldTerminateController;
  1385. if (v3_cpp_obj_query_interface(component, v3_edit_controller_iid, &controller) != V3_OK)
  1386. controller = nullptr;
  1387. if (controller != nullptr)
  1388. {
  1389. // got edit controller from casting component, assume they belong to the same object
  1390. shouldTerminateController = false;
  1391. }
  1392. else
  1393. {
  1394. // try to create edit controller from factory
  1395. v3_tuid uid = {};
  1396. if (v3_cpp_obj(component)->get_controller_class_id(component, uid) == V3_OK)
  1397. {
  1398. instance = nullptr;
  1399. if (v3_cpp_obj(factory1)->create_instance(factory1, uid, v3_edit_controller_iid, &instance) == V3_OK)
  1400. controller = static_cast<v3_edit_controller**>(instance);
  1401. }
  1402. if (controller == nullptr)
  1403. {
  1404. DISCOVERY_OUT("warning", "Plugin '" << classInfo.v1.name << "' does not have an edit controller");
  1405. v3_cpp_obj_terminate(component);
  1406. v3_cpp_obj_unref(component);
  1407. continue;
  1408. }
  1409. // component is separate from controller, needs its dedicated initialize and terminate
  1410. shouldTerminateController = true;
  1411. v3_cpp_obj_initialize(controller, hostContext);
  1412. }
  1413. // connect component to controller
  1414. v3_connection_point** connComponent = nullptr;
  1415. if (v3_cpp_obj_query_interface(component, v3_connection_point_iid, &connComponent) != V3_OK)
  1416. connComponent = nullptr;
  1417. v3_connection_point** connController = nullptr;
  1418. if (v3_cpp_obj_query_interface(controller, v3_connection_point_iid, &connController) != V3_OK)
  1419. connController = nullptr;
  1420. if (connComponent != nullptr && connController != nullptr)
  1421. {
  1422. v3_cpp_obj(connComponent)->connect(connComponent, connController);
  1423. v3_cpp_obj(connController)->connect(connController, connComponent);
  1424. }
  1425. // fill in all the details
  1426. uint hints = 0x0;
  1427. int audioIns = 0;
  1428. int audioOuts = 0;
  1429. int cvIns = 0;
  1430. int cvOuts = 0;
  1431. int parameterIns = 0;
  1432. int parameterOuts = 0;
  1433. const int32_t numAudioInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_INPUT);
  1434. const int32_t numEventInputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_INPUT);
  1435. const int32_t numAudioOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_AUDIO, V3_OUTPUT);
  1436. const int32_t numEventOutputBuses = v3_cpp_obj(component)->get_bus_count(component, V3_EVENT, V3_OUTPUT);
  1437. const int32_t numParameters = v3_cpp_obj(controller)->get_parameter_count(controller);
  1438. CARLA_SAFE_ASSERT(numAudioInputBuses >= 0);
  1439. CARLA_SAFE_ASSERT(numEventInputBuses >= 0);
  1440. CARLA_SAFE_ASSERT(numAudioOutputBuses >= 0);
  1441. CARLA_SAFE_ASSERT(numEventOutputBuses >= 0);
  1442. CARLA_SAFE_ASSERT(numParameters >= 0);
  1443. for (int32_t b=0; b<numAudioInputBuses; ++b)
  1444. {
  1445. v3_bus_info busInfo = {};
  1446. res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, b, &busInfo);
  1447. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1448. if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
  1449. cvIns += busInfo.channel_count;
  1450. else
  1451. audioIns += busInfo.channel_count;
  1452. }
  1453. for (int32_t b=0; b<numAudioOutputBuses; ++b)
  1454. {
  1455. v3_bus_info busInfo = {};
  1456. res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, b, &busInfo);
  1457. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1458. if (busInfo.flags & V3_IS_CONTROL_VOLTAGE)
  1459. cvOuts += busInfo.channel_count;
  1460. else
  1461. audioOuts += busInfo.channel_count;
  1462. }
  1463. for (int32_t p=0; p<numParameters; ++p)
  1464. {
  1465. v3_param_info paramInfo = {};
  1466. res = v3_cpp_obj(controller)->get_parameter_info(controller, p, &paramInfo);
  1467. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1468. if (paramInfo.flags & (V3_PARAM_IS_BYPASS|V3_PARAM_IS_HIDDEN|V3_PARAM_PROGRAM_CHANGE))
  1469. continue;
  1470. if (paramInfo.flags & V3_PARAM_READ_ONLY)
  1471. ++parameterOuts;
  1472. else
  1473. ++parameterIns;
  1474. }
  1475. CARLA_SAFE_ASSERT_CONTINUE(audioIns <= MAX_DISCOVERY_AUDIO_IO);
  1476. CARLA_SAFE_ASSERT_CONTINUE(audioOuts <= MAX_DISCOVERY_AUDIO_IO);
  1477. CARLA_SAFE_ASSERT_CONTINUE(cvIns <= MAX_DISCOVERY_CV_IO);
  1478. CARLA_SAFE_ASSERT_CONTINUE(cvOuts <= MAX_DISCOVERY_CV_IO);
  1479. #ifdef V3_VIEW_PLATFORM_TYPE_NATIVE
  1480. if (v3_plugin_view** const view = v3_cpp_obj(controller)->create_view(controller, "editor"))
  1481. {
  1482. if (v3_cpp_obj(view)->is_platform_type_supported(view, V3_VIEW_PLATFORM_TYPE_NATIVE) == V3_TRUE)
  1483. {
  1484. hints |= PLUGIN_HAS_CUSTOM_UI;
  1485. #ifndef BUILD_BRIDGE
  1486. hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  1487. #endif
  1488. }
  1489. v3_cpp_obj_unref(view);
  1490. }
  1491. #endif
  1492. if (factory2 != nullptr && std::strstr(classInfo.v2.sub_categories, "Instrument") != nullptr)
  1493. hints |= PLUGIN_IS_SYNTH;
  1494. if (doInit)
  1495. {
  1496. v3_audio_processor** processor = nullptr;
  1497. v3_process_setup setup = { V3_REALTIME, V3_SAMPLE_32, kBufferSize, kSampleRate };
  1498. res = v3_cpp_obj_query_interface(component, v3_audio_processor_iid, &processor);
  1499. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1500. CARLA_SAFE_ASSERT_BREAK(processor != nullptr);
  1501. res = v3_cpp_obj(processor)->can_process_sample_size(processor, V3_SAMPLE_32);
  1502. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1503. res = v3_cpp_obj(component)->set_active(component, true);
  1504. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1505. res = v3_cpp_obj(processor)->setup_processing(processor, &setup);
  1506. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1507. res = v3_cpp_obj(component)->set_active(component, false);
  1508. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1509. v3_audio_bus_buffers* const inputsBuffers = numAudioInputBuses > 0
  1510. ? new v3_audio_bus_buffers[numAudioInputBuses]
  1511. : nullptr;
  1512. v3_audio_bus_buffers* const outputsBuffers = numAudioOutputBuses > 0
  1513. ? new v3_audio_bus_buffers[numAudioOutputBuses]
  1514. : nullptr;
  1515. for (int32_t b=0; b<numAudioInputBuses; ++b)
  1516. {
  1517. v3_bus_info busInfo = {};
  1518. carla_zeroStruct(inputsBuffers[b]);
  1519. res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_INPUT, b, &busInfo);
  1520. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1521. res = v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_INPUT, b, true);
  1522. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1523. inputsBuffers[b].num_channels = busInfo.channel_count;
  1524. }
  1525. for (int32_t b=0; b<numAudioOutputBuses; ++b)
  1526. {
  1527. v3_bus_info busInfo = {};
  1528. carla_zeroStruct(outputsBuffers[b]);
  1529. res = v3_cpp_obj(component)->get_bus_info(component, V3_AUDIO, V3_OUTPUT, b, &busInfo);
  1530. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1531. res = v3_cpp_obj(component)->activate_bus(component, V3_AUDIO, V3_OUTPUT, b, true);
  1532. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1533. outputsBuffers[b].num_channels = busInfo.channel_count;
  1534. }
  1535. res = v3_cpp_obj(component)->set_active(component, true);
  1536. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1537. res = v3_cpp_obj(processor)->set_processing(processor, true);
  1538. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK || res == V3_NOT_IMPLEMENTED, res);
  1539. float* bufferAudioIn[MAX_DISCOVERY_AUDIO_IO + MAX_DISCOVERY_CV_IO];
  1540. float* bufferAudioOut[MAX_DISCOVERY_AUDIO_IO + MAX_DISCOVERY_CV_IO];
  1541. for (int j=0; j < audioIns + cvIns; ++j)
  1542. {
  1543. bufferAudioIn[j] = new float[kBufferSize];
  1544. carla_zeroFloats(bufferAudioIn[j], kBufferSize);
  1545. }
  1546. for (int j=0; j < audioOuts + cvOuts; ++j)
  1547. {
  1548. bufferAudioOut[j] = new float[kBufferSize];
  1549. carla_zeroFloats(bufferAudioOut[j], kBufferSize);
  1550. }
  1551. for (int32_t b = 0, j = 0; b < numAudioInputBuses; ++b)
  1552. {
  1553. inputsBuffers[b].channel_buffers_32 = bufferAudioIn + j;
  1554. j += inputsBuffers[b].num_channels;
  1555. }
  1556. for (int32_t b = 0, j = 0; b < numAudioOutputBuses; ++b)
  1557. {
  1558. outputsBuffers[b].channel_buffers_32 = bufferAudioOut + j;
  1559. j += outputsBuffers[b].num_channels;
  1560. }
  1561. carla_v3_event_list eventList;
  1562. carla_v3_event_list* eventListPtr = &eventList;
  1563. carla_v3_param_changes paramChanges;
  1564. carla_v3_param_changes* paramChangesPtr = &paramChanges;
  1565. v3_process_context processContext = {};
  1566. processContext.sample_rate = kSampleRate;
  1567. v3_process_data processData = {
  1568. V3_REALTIME,
  1569. V3_SAMPLE_32,
  1570. kBufferSize,
  1571. numAudioInputBuses,
  1572. numAudioOutputBuses,
  1573. inputsBuffers,
  1574. outputsBuffers,
  1575. (v3_param_changes**)&paramChangesPtr,
  1576. (v3_param_changes**)&paramChangesPtr,
  1577. (v3_event_list**)&eventListPtr,
  1578. (v3_event_list**)&eventListPtr,
  1579. &processContext
  1580. };
  1581. res = v3_cpp_obj(processor)->process(processor, &processData);
  1582. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1583. delete[] inputsBuffers;
  1584. delete[] outputsBuffers;
  1585. for (int j=0; j < audioIns + cvIns; ++j)
  1586. delete[] bufferAudioIn[j];
  1587. for (int j=0; j < audioOuts + cvOuts; ++j)
  1588. delete[] bufferAudioOut[j];
  1589. res = v3_cpp_obj(processor)->set_processing(processor, false);
  1590. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK || res == V3_NOT_IMPLEMENTED, res);
  1591. res = v3_cpp_obj(component)->set_active(component, false);
  1592. CARLA_SAFE_ASSERT_INT_BREAK(res == V3_OK, res);
  1593. v3_cpp_obj_unref(processor);
  1594. }
  1595. // disconnect and unref connection points
  1596. if (connComponent != nullptr && connController != nullptr)
  1597. {
  1598. v3_cpp_obj(connComponent)->disconnect(connComponent, connController);
  1599. v3_cpp_obj(connController)->disconnect(connController, connComponent);
  1600. }
  1601. if (connComponent != nullptr)
  1602. v3_cpp_obj_unref(connComponent);
  1603. if (connController != nullptr)
  1604. v3_cpp_obj_unref(connController);
  1605. if (shouldTerminateController)
  1606. v3_cpp_obj_terminate(controller);
  1607. v3_cpp_obj_unref(controller);
  1608. v3_cpp_obj_terminate(component);
  1609. v3_cpp_obj_unref(component);
  1610. DISCOVERY_OUT("init", "------------");
  1611. DISCOVERY_OUT("build", BINARY_NATIVE);
  1612. DISCOVERY_OUT("hints", hints);
  1613. DISCOVERY_OUT("category", getPluginCategoryAsString(factory2 != nullptr ? getPluginCategoryFromV3SubCategories(classInfo.v2.sub_categories)
  1614. : getPluginCategoryFromName(classInfo.v1.name)));
  1615. DISCOVERY_OUT("name", classInfo.v1.name);
  1616. DISCOVERY_OUT("label", tuid2str(classInfo.v1.class_id));
  1617. DISCOVERY_OUT("maker", (factory2 != nullptr ? classInfo.v2.vendor : factoryInfo.vendor));
  1618. DISCOVERY_OUT("audio.ins", audioIns);
  1619. DISCOVERY_OUT("audio.outs", audioOuts);
  1620. DISCOVERY_OUT("cv.ins", cvIns);
  1621. DISCOVERY_OUT("cv.outs", cvOuts);
  1622. DISCOVERY_OUT("midi.ins", numEventInputBuses);
  1623. DISCOVERY_OUT("midi.outs", numEventOutputBuses);
  1624. DISCOVERY_OUT("parameters.ins", parameterIns);
  1625. DISCOVERY_OUT("parameters.outs", parameterOuts);
  1626. DISCOVERY_OUT("end", "------------");
  1627. }
  1628. // unref interfaces
  1629. if (factory3 != nullptr)
  1630. v3_cpp_obj_unref(factory3);
  1631. if (factory2 != nullptr)
  1632. v3_cpp_obj_unref(factory2);
  1633. v3_cpp_obj_unref(factory1);
  1634. v3_exit();
  1635. return false;
  1636. }
  1637. // --------------------------------------------------------------------------------------------------------------------
  1638. // AU
  1639. #ifdef CARLA_OS_MAC
  1640. typedef AudioComponentPlugInInterface* (*FactoryFn)(const AudioComponentDescription*);
  1641. typedef OSStatus (*InitializeFn)(void*);
  1642. typedef OSStatus (*UninitializeFn)(void*);
  1643. typedef OSStatus (*GetPropertyInfoFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, UInt32*, Boolean*);
  1644. typedef OSStatus (*GetPropertyFn)(void*, AudioUnitPropertyID, AudioUnitScope, AudioUnitElement, void*, UInt32*);
  1645. typedef OSStatus (*MIDIEventFn)(void*, UInt32, UInt32, UInt32, UInt32);
  1646. static constexpr FourCharCode getFourCharCodeFromString(const char str[4])
  1647. {
  1648. return (str[0] << 24) + (str[1] << 16) + (str[2] << 8) + str[3];
  1649. }
  1650. static bool do_au_check(const char* const filename, const bool doInit)
  1651. {
  1652. BundleLoader bundleLoader;
  1653. if (! bundleLoader.load(filename))
  1654. {
  1655. #ifdef __aarch64__
  1656. return true;
  1657. #else
  1658. DISCOVERY_OUT("error", "Failed to load AU bundle executable");
  1659. return false;
  1660. #endif
  1661. }
  1662. const CFTypeRef componentsRef = CFBundleGetValueForInfoDictionaryKey(bundleLoader.getRef(), CFSTR("AudioComponents"));
  1663. if (componentsRef == nullptr || CFGetTypeID(componentsRef) != CFArrayGetTypeID())
  1664. {
  1665. DISCOVERY_OUT("error", "Not an AU component");
  1666. return false;
  1667. }
  1668. const CFArrayRef components = static_cast<CFArrayRef>(componentsRef);
  1669. for (uint32_t c = 0, count = CFArrayGetCount(components); c < count; ++c)
  1670. {
  1671. const CFTypeRef componentRef = CFArrayGetValueAtIndex(components, c);
  1672. CARLA_SAFE_ASSERT_CONTINUE(componentRef != nullptr);
  1673. CARLA_SAFE_ASSERT_CONTINUE(CFGetTypeID(componentRef) == CFDictionaryGetTypeID());
  1674. const CFDictionaryRef component = static_cast<CFDictionaryRef>(componentRef);
  1675. CFStringRef componentName = nullptr;
  1676. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("name"), (const void **)&componentName));
  1677. CFStringRef componentFactoryFunction = nullptr;
  1678. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("factoryFunction"), (const void **)&componentFactoryFunction));
  1679. CFStringRef componentType = nullptr;
  1680. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("type"), (const void **)&componentType));
  1681. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentType) == 4);
  1682. CFStringRef componentSubType = nullptr;
  1683. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("subtype"), (const void **)&componentSubType));
  1684. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentSubType) == 4);
  1685. CFStringRef componentManufacturer = nullptr;
  1686. CARLA_SAFE_ASSERT_CONTINUE(CFDictionaryGetValueIfPresent(component, CFSTR("manufacturer"), (const void **)&componentManufacturer));
  1687. CARLA_SAFE_ASSERT_CONTINUE(CFStringGetLength(componentManufacturer) == 4);
  1688. const FactoryFn factoryFn = bundleLoader.getSymbol<FactoryFn>(componentFactoryFunction);
  1689. CARLA_SAFE_ASSERT_CONTINUE(factoryFn != nullptr);
  1690. char label[15] = {};
  1691. CFStringGetCString(componentType, label, 5, kCFStringEncodingASCII);
  1692. CFStringGetCString(componentSubType, label + 5, 5, kCFStringEncodingASCII);
  1693. CFStringGetCString(componentManufacturer, label + 10, 5, kCFStringEncodingASCII);
  1694. const AudioComponentDescription desc = {
  1695. getFourCharCodeFromString(label),
  1696. getFourCharCodeFromString(label + 5),
  1697. getFourCharCodeFromString(label + 10),
  1698. 0, 0
  1699. };
  1700. CARLA_SAFE_ASSERT_CONTINUE(desc.componentType != 0);
  1701. CARLA_SAFE_ASSERT_CONTINUE(desc.componentSubType != 0);
  1702. CARLA_SAFE_ASSERT_CONTINUE(desc.componentManufacturer != 0);
  1703. label[4] = label[9] = ',';
  1704. AudioComponentPlugInInterface* const interface = factoryFn(&desc);
  1705. CARLA_SAFE_ASSERT_CONTINUE(interface != nullptr);
  1706. const InitializeFn auInitialize = (InitializeFn)interface->Lookup(kAudioUnitInitializeSelect);
  1707. const UninitializeFn auUninitialize = (UninitializeFn)interface->Lookup(kAudioUnitUninitializeSelect);
  1708. const GetPropertyInfoFn auGetPropertyInfo = (GetPropertyInfoFn)interface->Lookup(kAudioUnitGetPropertyInfoSelect);
  1709. const GetPropertyFn auGetProperty = (GetPropertyFn)interface->Lookup(kAudioUnitGetPropertySelect);
  1710. const MIDIEventFn auMIDIEvent = (MIDIEventFn)interface->Lookup(kMusicDeviceMIDIEventSelect);
  1711. if (auInitialize == nullptr || auUninitialize == nullptr)
  1712. continue;
  1713. if (auGetPropertyInfo == nullptr || auGetProperty == nullptr)
  1714. continue;
  1715. if (interface->Open(interface, (AudioUnit)(void*)0x1) == noErr)
  1716. {
  1717. uint hints = 0x0;
  1718. uint audioIns = 0;
  1719. uint audioOuts = 0;
  1720. uint midiIns = 0;
  1721. uint midiOuts = 0;
  1722. uint parametersIns = 0;
  1723. uint parametersOuts = 0;
  1724. PluginCategory category;
  1725. switch (desc.componentType)
  1726. {
  1727. case kAudioUnitType_Effect:
  1728. case kAudioUnitType_MusicEffect:
  1729. category = PLUGIN_CATEGORY_NONE;
  1730. break;
  1731. case kAudioUnitType_Generator:
  1732. case kAudioUnitType_MusicDevice:
  1733. category = PLUGIN_CATEGORY_SYNTH;
  1734. break;
  1735. case kAudioUnitType_MIDIProcessor:
  1736. case kAudioUnitType_Mixer:
  1737. case kAudioUnitType_Panner:
  1738. case kAudioUnitType_SpeechSynthesizer:
  1739. category = PLUGIN_CATEGORY_UTILITY;
  1740. break;
  1741. case kAudioUnitType_FormatConverter:
  1742. case kAudioUnitType_OfflineEffect:
  1743. case kAudioUnitType_Output:
  1744. category = PLUGIN_CATEGORY_OTHER;
  1745. break;
  1746. default:
  1747. category = PLUGIN_CATEGORY_NONE;
  1748. break;
  1749. }
  1750. UInt32 outDataSize;
  1751. Boolean outWritable = false;
  1752. // audio port count
  1753. outDataSize = 0;
  1754. if (auGetPropertyInfo(interface,
  1755. kAudioUnitProperty_SupportedNumChannels,
  1756. kAudioUnitScope_Global,
  1757. 0, &outDataSize, &outWritable) == noErr
  1758. && outDataSize != 0
  1759. && outDataSize % sizeof(AUChannelInfo) == 0)
  1760. {
  1761. const uint32_t numChannels = outDataSize / sizeof(AUChannelInfo);
  1762. AUChannelInfo* const channelInfo = new AUChannelInfo[numChannels];
  1763. if (auGetProperty(interface,
  1764. kAudioUnitProperty_SupportedNumChannels,
  1765. kAudioUnitScope_Global,
  1766. 0, channelInfo, &outDataSize) == noErr
  1767. && outDataSize == numChannels * sizeof(AUChannelInfo))
  1768. {
  1769. AUChannelInfo* highestInfo = &channelInfo[0];
  1770. for (uint32_t i=0; i<numChannels; ++i)
  1771. {
  1772. if (channelInfo[i].inChannels < 0)
  1773. channelInfo[i].inChannels = 2;
  1774. if (channelInfo[i].outChannels < 0)
  1775. channelInfo[i].outChannels = 2;
  1776. if (channelInfo[i].inChannels > highestInfo->inChannels
  1777. && channelInfo[i].outChannels > highestInfo->outChannels)
  1778. {
  1779. highestInfo = &channelInfo[i];
  1780. }
  1781. }
  1782. audioIns = std::min<int16_t>(64, highestInfo->inChannels);
  1783. audioOuts = std::min<int16_t>(64, highestInfo->outChannels);
  1784. }
  1785. delete[] channelInfo;
  1786. }
  1787. else
  1788. {
  1789. // unsupported for now
  1790. interface->Close(interface);
  1791. continue;
  1792. outDataSize = 0;
  1793. if (auGetPropertyInfo(interface,
  1794. kAudioUnitProperty_ElementCount,
  1795. kAudioUnitScope_Input,
  1796. 0, &outDataSize, &outWritable) == noErr
  1797. && outDataSize == sizeof(UInt32))
  1798. {
  1799. UInt32 count = 0;
  1800. if (auGetProperty(interface,
  1801. kAudioUnitProperty_ElementCount,
  1802. kAudioUnitScope_Input,
  1803. 0, &count, &outDataSize) == noErr
  1804. && outDataSize == sizeof(UInt32) && count != 0)
  1805. {
  1806. AudioStreamBasicDescription desc;
  1807. std::memset(&desc, 0, sizeof(desc));
  1808. outDataSize = sizeof(AudioStreamBasicDescription);
  1809. if (auGetProperty(interface,
  1810. kAudioUnitProperty_StreamFormat,
  1811. kAudioUnitScope_Input,
  1812. 0, &desc, &outDataSize) == noErr)
  1813. audioIns = std::min<uint32_t>(64, desc.mChannelsPerFrame);
  1814. }
  1815. }
  1816. outDataSize = 0;
  1817. if (auGetPropertyInfo(interface,
  1818. kAudioUnitProperty_ElementCount,
  1819. kAudioUnitScope_Output,
  1820. 0, &outDataSize, &outWritable) == noErr
  1821. && outDataSize == sizeof(UInt32))
  1822. {
  1823. UInt32 count = 0;
  1824. if (auGetProperty(interface,
  1825. kAudioUnitProperty_ElementCount,
  1826. kAudioUnitScope_Output,
  1827. 0, &count, &outDataSize) == noErr
  1828. && outDataSize == sizeof(UInt32) && count != 0)
  1829. {
  1830. AudioStreamBasicDescription desc;
  1831. std::memset(&desc, 0, sizeof(desc));
  1832. outDataSize = sizeof(AudioStreamBasicDescription);
  1833. if (auGetProperty(interface,
  1834. kAudioUnitProperty_StreamFormat,
  1835. kAudioUnitScope_Output,
  1836. 0, &desc, &outDataSize) == noErr)
  1837. audioOuts = std::min<uint32_t>(64, desc.mChannelsPerFrame);
  1838. }
  1839. }
  1840. }
  1841. // parameter count
  1842. outDataSize = 0;
  1843. if (auGetPropertyInfo(interface,
  1844. kAudioUnitProperty_ParameterList,
  1845. kAudioUnitScope_Global,
  1846. 0, &outDataSize, &outWritable) == noErr
  1847. && outDataSize != 0
  1848. && outDataSize % sizeof(AudioUnitParameterID) == 0)
  1849. {
  1850. const uint32_t numParams = outDataSize / sizeof(AudioUnitParameterID);
  1851. AudioUnitParameterID* const paramIds = new AudioUnitParameterID[numParams];
  1852. if (auGetProperty(interface,
  1853. kAudioUnitProperty_ParameterList,
  1854. kAudioUnitScope_Global,
  1855. 0, paramIds, &outDataSize) == noErr
  1856. && outDataSize == numParams * sizeof(AudioUnitParameterID))
  1857. {
  1858. AudioUnitParameterInfo info;
  1859. for (uint32_t i=0; i<numParams; ++i)
  1860. {
  1861. carla_zeroStruct(info);
  1862. outDataSize = 0;
  1863. if (auGetPropertyInfo(interface,
  1864. kAudioUnitProperty_ParameterInfo,
  1865. kAudioUnitScope_Global,
  1866. paramIds[i], &outDataSize, &outWritable) != noErr)
  1867. break;
  1868. if (outDataSize != sizeof(AudioUnitParameterInfo))
  1869. break;
  1870. if (auGetProperty(interface,
  1871. kAudioUnitProperty_ParameterInfo,
  1872. kAudioUnitScope_Global,
  1873. paramIds[i], &info, &outDataSize) != noErr)
  1874. break;
  1875. if ((info.flags & kAudioUnitParameterFlag_IsReadable) == 0)
  1876. continue;
  1877. if (info.flags & kAudioUnitParameterFlag_IsWritable)
  1878. ++parametersIns;
  1879. else
  1880. ++parametersOuts;
  1881. }
  1882. }
  1883. delete[] paramIds;
  1884. }
  1885. // MIDI input
  1886. if (auMIDIEvent != nullptr && auInitialize(interface) == noErr)
  1887. {
  1888. if (auMIDIEvent(interface, 0x90, 60, 64, 0) == noErr)
  1889. midiIns = 1;
  1890. auUninitialize(interface);
  1891. }
  1892. // MIDI output
  1893. outDataSize = 0;
  1894. outWritable = false;
  1895. if (auGetPropertyInfo(interface,
  1896. kAudioUnitProperty_MIDIOutputCallback,
  1897. kAudioUnitScope_Global,
  1898. 0, &outDataSize, &outWritable) == noErr
  1899. && outDataSize == sizeof(AUMIDIOutputCallbackStruct)
  1900. && outWritable)
  1901. {
  1902. midiOuts = 1;
  1903. }
  1904. // hints
  1905. if (category == PLUGIN_CATEGORY_SYNTH)
  1906. hints |= PLUGIN_IS_SYNTH;
  1907. outDataSize = 0;
  1908. if (auGetPropertyInfo(interface,
  1909. kAudioUnitProperty_CocoaUI,
  1910. kAudioUnitScope_Global,
  1911. 0, &outDataSize, &outWritable) == noErr
  1912. && outDataSize == sizeof(AudioUnitCocoaViewInfo))
  1913. {
  1914. hints |= PLUGIN_HAS_CUSTOM_UI;
  1915. #ifndef BUILD_BRIDGE
  1916. /* FIXME only enable this after doing custom AU hosting
  1917. hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  1918. */
  1919. #endif
  1920. }
  1921. if (doInit)
  1922. {
  1923. // TODO tests
  1924. }
  1925. const CFIndex componentNameLen = CFStringGetLength(componentName);
  1926. char* const nameBuffer = new char[componentNameLen + 1];
  1927. const char* name;
  1928. const char* maker;
  1929. if (CFStringGetCString(componentName, nameBuffer, componentNameLen + 1, kCFStringEncodingUTF8))
  1930. {
  1931. if (char* const sep = std::strstr(nameBuffer, ": "))
  1932. {
  1933. sep[0] = sep[1] = '\0';
  1934. name = sep + 2;
  1935. maker = nameBuffer;
  1936. }
  1937. else
  1938. {
  1939. name = nameBuffer;
  1940. maker = nameBuffer + componentNameLen;
  1941. }
  1942. }
  1943. else
  1944. {
  1945. nameBuffer[0] = '\0';
  1946. name = maker = nameBuffer;
  1947. }
  1948. interface->Close(interface);
  1949. DISCOVERY_OUT("init", "------------");
  1950. DISCOVERY_OUT("build", BINARY_NATIVE);
  1951. DISCOVERY_OUT("hints", hints);
  1952. DISCOVERY_OUT("category", getPluginCategoryAsString(category));
  1953. DISCOVERY_OUT("name", name);
  1954. DISCOVERY_OUT("label", label);
  1955. DISCOVERY_OUT("maker", maker);
  1956. DISCOVERY_OUT("audio.ins", audioIns);
  1957. DISCOVERY_OUT("audio.outs", audioOuts);
  1958. DISCOVERY_OUT("midi.ins", midiIns);
  1959. DISCOVERY_OUT("midi.outs", midiOuts);
  1960. DISCOVERY_OUT("parameters.ins", parametersIns);
  1961. DISCOVERY_OUT("parameters.outs", parametersOuts);
  1962. DISCOVERY_OUT("end", "------------");
  1963. delete[] nameBuffer;
  1964. }
  1965. }
  1966. return false;
  1967. }
  1968. #endif // CARLA_OS_MAC
  1969. // --------------------------------------------------------------------------------------------------------------------
  1970. // CLAP
  1971. struct carla_clap_host : clap_host_t {
  1972. carla_clap_host()
  1973. {
  1974. clap_version = CLAP_VERSION;
  1975. host_data = this;
  1976. name = "Carla-Discovery";
  1977. vendor = "falkTX";
  1978. url = "https://kx.studio/carla";
  1979. version = CARLA_VERSION_STRING;
  1980. get_extension = carla_get_extension;
  1981. request_restart = carla_request_restart;
  1982. request_process = carla_request_process;
  1983. request_callback = carla_request_callback;
  1984. }
  1985. private:
  1986. static const void* CLAP_ABI carla_get_extension(const clap_host_t* const host, const char* const extension_id)
  1987. {
  1988. carla_stdout("carla_get_extension %p %s", host, extension_id);
  1989. return nullptr;
  1990. }
  1991. static void CLAP_ABI carla_request_restart(const clap_host_t* const host)
  1992. {
  1993. carla_stdout("carla_request_restart %p", host);
  1994. }
  1995. static void CLAP_ABI carla_request_process(const clap_host_t* const host)
  1996. {
  1997. carla_stdout("carla_request_process %p", host);
  1998. }
  1999. static void CLAP_ABI carla_request_callback(const clap_host_t* const host)
  2000. {
  2001. carla_stdout("carla_request_callback %p", host);
  2002. }
  2003. };
  2004. static bool clap_deinit_false(const clap_plugin_entry_t* const entry)
  2005. {
  2006. entry->deinit();
  2007. return false;
  2008. }
  2009. static bool do_clap_check(lib_t& libHandle, const char* const filename, const bool doInit)
  2010. {
  2011. const clap_plugin_entry_t* entry = nullptr;
  2012. #ifdef CARLA_OS_MAC
  2013. BundleLoader bundleLoader;
  2014. // if passed filename is not a plugin binary directly, inspect bundle and find one
  2015. if (libHandle == nullptr)
  2016. {
  2017. if (! bundleLoader.load(filename))
  2018. {
  2019. #ifdef __aarch64__
  2020. return true;
  2021. #else
  2022. DISCOVERY_OUT("error", "Failed to load CLAP bundle executable");
  2023. return false;
  2024. #endif
  2025. }
  2026. entry = bundleLoader.getSymbol<const clap_plugin_entry_t*>(CFSTR("clap_entry"));
  2027. }
  2028. else
  2029. #endif
  2030. {
  2031. entry = lib_symbol<const clap_plugin_entry_t*>(libHandle, "clap_entry");
  2032. }
  2033. // ensure entry points are available
  2034. if (entry == nullptr || entry->init == nullptr || entry->deinit == nullptr || entry->get_factory == nullptr)
  2035. {
  2036. DISCOVERY_OUT("error", "Not a CLAP plugin");
  2037. return false;
  2038. }
  2039. // ensure compatible version
  2040. if (!clap_version_is_compatible(entry->clap_version))
  2041. {
  2042. DISCOVERY_OUT("error", "Incompatible CLAP plugin");
  2043. return false;
  2044. }
  2045. const water::String pluginPath(water::File(filename).getParentDirectory().getFullPathName());
  2046. if (!entry->init(pluginPath.toRawUTF8()))
  2047. {
  2048. DISCOVERY_OUT("error", "CLAP plugin failed to initialize");
  2049. return false;
  2050. }
  2051. const clap_plugin_factory_t* const factory = static_cast<const clap_plugin_factory_t*>(
  2052. entry->get_factory(CLAP_PLUGIN_FACTORY_ID));
  2053. CARLA_SAFE_ASSERT_RETURN(factory != nullptr
  2054. && factory->get_plugin_count != nullptr
  2055. && factory->get_plugin_descriptor != nullptr
  2056. && factory->create_plugin != nullptr, clap_deinit_false(entry));
  2057. if (const uint32_t count = factory->get_plugin_count(factory))
  2058. {
  2059. const carla_clap_host host;
  2060. for (uint32_t i=0; i<count; ++i)
  2061. {
  2062. const clap_plugin_descriptor_t* const desc = factory->get_plugin_descriptor(factory, i);
  2063. CARLA_SAFE_ASSERT_CONTINUE(desc != nullptr);
  2064. const clap_plugin_t* const plugin = factory->create_plugin(factory, &host, desc->id);
  2065. CARLA_SAFE_ASSERT_CONTINUE(plugin != nullptr);
  2066. // FIXME this is not needed per spec, but JUCE-based CLAP plugins crash without it :(
  2067. if (!plugin->init(plugin))
  2068. {
  2069. plugin->destroy(plugin);
  2070. continue;
  2071. }
  2072. uint hints = 0x0;
  2073. uint audioIns = 0;
  2074. uint audioOuts = 0;
  2075. uint midiIns = 0;
  2076. uint midiOuts = 0;
  2077. uint parametersIns = 0;
  2078. uint parametersOuts = 0;
  2079. PluginCategory category = PLUGIN_CATEGORY_NONE;
  2080. const clap_plugin_audio_ports_t* const audioPorts = static_cast<const clap_plugin_audio_ports_t*>(
  2081. plugin->get_extension(plugin, CLAP_EXT_AUDIO_PORTS));
  2082. const clap_plugin_note_ports_t* const notePorts = static_cast<const clap_plugin_note_ports_t*>(
  2083. plugin->get_extension(plugin, CLAP_EXT_NOTE_PORTS));
  2084. const clap_plugin_params_t* const params = static_cast<const clap_plugin_params_t*>(
  2085. plugin->get_extension(plugin, CLAP_EXT_PARAMS));
  2086. #ifdef CLAP_WINDOW_API_NATIVE
  2087. const clap_plugin_gui_t* const gui = static_cast<const clap_plugin_gui_t*>(
  2088. plugin->get_extension(plugin, CLAP_EXT_GUI));
  2089. #endif
  2090. if (audioPorts != nullptr)
  2091. {
  2092. clap_audio_port_info_t info;
  2093. const uint32_t inPorts = audioPorts->count(plugin, true);
  2094. for (uint32_t j=0; j<inPorts; ++j)
  2095. {
  2096. if (!audioPorts->get(plugin, j, true, &info))
  2097. break;
  2098. audioIns += info.channel_count;
  2099. }
  2100. const uint32_t outPorts = audioPorts->count(plugin, false);
  2101. for (uint32_t j=0; j<outPorts; ++j)
  2102. {
  2103. if (!audioPorts->get(plugin, j, false, &info))
  2104. break;
  2105. audioOuts += info.channel_count;
  2106. }
  2107. }
  2108. if (notePorts != nullptr)
  2109. {
  2110. clap_note_port_info_t info;
  2111. const uint32_t inPorts = notePorts->count(plugin, true);
  2112. for (uint32_t j=0; j<inPorts; ++j)
  2113. {
  2114. if (!notePorts->get(plugin, j, true, &info))
  2115. break;
  2116. if (info.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
  2117. ++midiIns;
  2118. }
  2119. const uint32_t outPorts = notePorts->count(plugin, false);
  2120. for (uint32_t j=0; j<outPorts; ++j)
  2121. {
  2122. if (!notePorts->get(plugin, j, false, &info))
  2123. break;
  2124. if (info.supported_dialects & CLAP_NOTE_DIALECT_MIDI)
  2125. ++midiOuts;
  2126. }
  2127. }
  2128. if (params != nullptr)
  2129. {
  2130. clap_param_info_t info;
  2131. const uint32_t numParams = params->count(plugin);
  2132. for (uint32_t j=0; j<numParams; ++j)
  2133. {
  2134. if (!params->get_info(plugin, j, &info))
  2135. break;
  2136. if (info.flags & (CLAP_PARAM_IS_HIDDEN|CLAP_PARAM_IS_BYPASS))
  2137. continue;
  2138. if (info.flags & CLAP_PARAM_IS_READONLY)
  2139. ++parametersOuts;
  2140. else
  2141. ++parametersIns;
  2142. }
  2143. }
  2144. if (desc->features != nullptr)
  2145. category = getPluginCategoryFromClapFeatures(desc->features);
  2146. if (category == PLUGIN_CATEGORY_SYNTH)
  2147. hints |= PLUGIN_IS_SYNTH;
  2148. #ifdef CLAP_WINDOW_API_NATIVE
  2149. if (gui != nullptr)
  2150. {
  2151. hints |= PLUGIN_HAS_CUSTOM_UI;
  2152. #ifndef BUILD_BRIDGE
  2153. if (gui->is_api_supported(plugin, CLAP_WINDOW_API_NATIVE, false))
  2154. hints |= PLUGIN_HAS_CUSTOM_EMBED_UI;
  2155. #endif
  2156. }
  2157. #endif
  2158. if (doInit)
  2159. {
  2160. // -----------------------------------------------------------------------
  2161. // start crash-free plugin test
  2162. // FIXME already initiated before, because broken plugins etc
  2163. // plugin->init(plugin);
  2164. // TODO
  2165. // end crash-free plugin test
  2166. // -----------------------------------------------------------------------
  2167. }
  2168. plugin->destroy(plugin);
  2169. DISCOVERY_OUT("init", "------------");
  2170. DISCOVERY_OUT("build", BINARY_NATIVE);
  2171. DISCOVERY_OUT("hints", hints);
  2172. DISCOVERY_OUT("category", getPluginCategoryAsString(category));
  2173. DISCOVERY_OUT("name", desc->name);
  2174. DISCOVERY_OUT("label", desc->id);
  2175. DISCOVERY_OUT("maker", desc->vendor);
  2176. DISCOVERY_OUT("audio.ins", audioIns);
  2177. DISCOVERY_OUT("audio.outs", audioOuts);
  2178. DISCOVERY_OUT("midi.ins", midiIns);
  2179. DISCOVERY_OUT("midi.outs", midiOuts);
  2180. DISCOVERY_OUT("parameters.ins", parametersIns);
  2181. DISCOVERY_OUT("parameters.outs", parametersOuts);
  2182. DISCOVERY_OUT("end", "------------");
  2183. }
  2184. }
  2185. entry->deinit();
  2186. return false;
  2187. }
  2188. // --------------------------------------------------------------------------------------------------------------------
  2189. // fluidsynth (dls, sf2, sfz)
  2190. #ifdef HAVE_FLUIDSYNTH
  2191. static void do_fluidsynth_check(const char* const filename, const PluginType type, const bool doInit)
  2192. {
  2193. const water::File file(filename);
  2194. if (! file.existsAsFile())
  2195. {
  2196. DISCOVERY_OUT("error", "Requested file is not valid or does not exist");
  2197. return;
  2198. }
  2199. if (type == PLUGIN_SF2 && ! fluid_is_soundfont(filename))
  2200. {
  2201. DISCOVERY_OUT("error", "Not a SF2 file");
  2202. return;
  2203. }
  2204. int programs = 0;
  2205. if (doInit)
  2206. {
  2207. fluid_settings_t* const f_settings = new_fluid_settings();
  2208. CARLA_SAFE_ASSERT_RETURN(f_settings != nullptr,);
  2209. fluid_synth_t* const f_synth = new_fluid_synth(f_settings);
  2210. CARLA_SAFE_ASSERT_RETURN(f_synth != nullptr,);
  2211. const int f_id_test = fluid_synth_sfload(f_synth, filename, 0);
  2212. if (f_id_test < 0)
  2213. {
  2214. DISCOVERY_OUT("error", "Failed to load SF2 file");
  2215. return;
  2216. }
  2217. #if FLUIDSYNTH_VERSION_MAJOR >= 2
  2218. const int f_id = f_id_test;
  2219. #else
  2220. const uint f_id = static_cast<uint>(f_id_test);
  2221. #endif
  2222. if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id))
  2223. {
  2224. #if FLUIDSYNTH_VERSION_MAJOR >= 2
  2225. fluid_sfont_iteration_start(f_sfont);
  2226. for (; fluid_sfont_iteration_next(f_sfont);)
  2227. ++programs;
  2228. #else
  2229. fluid_preset_t f_preset;
  2230. f_sfont->iteration_start(f_sfont);
  2231. for (; f_sfont->iteration_next(f_sfont, &f_preset);)
  2232. ++programs;
  2233. #endif
  2234. }
  2235. delete_fluid_synth(f_synth);
  2236. delete_fluid_settings(f_settings);
  2237. }
  2238. CarlaString name(file.getFileNameWithoutExtension().toRawUTF8());
  2239. CarlaString label(name);
  2240. // 2 channels
  2241. DISCOVERY_OUT("init", "------------");
  2242. DISCOVERY_OUT("build", BINARY_NATIVE);
  2243. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  2244. DISCOVERY_OUT("category", "synth");
  2245. DISCOVERY_OUT("name", name.buffer());
  2246. DISCOVERY_OUT("label", label.buffer());
  2247. DISCOVERY_OUT("audio.outs", 2);
  2248. DISCOVERY_OUT("midi.ins", 1);
  2249. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  2250. DISCOVERY_OUT("parameters.outs", 1);
  2251. DISCOVERY_OUT("end", "------------");
  2252. // 16 channels
  2253. if (doInit && (name.isEmpty() || programs <= 1))
  2254. return;
  2255. name += " (16 outputs)";
  2256. DISCOVERY_OUT("init", "------------");
  2257. DISCOVERY_OUT("build", BINARY_NATIVE);
  2258. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  2259. DISCOVERY_OUT("category", "synth");
  2260. DISCOVERY_OUT("name", name.buffer());
  2261. DISCOVERY_OUT("label", label.buffer());
  2262. DISCOVERY_OUT("audio.outs", 32);
  2263. DISCOVERY_OUT("midi.ins", 1);
  2264. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  2265. DISCOVERY_OUT("parameters.outs", 1);
  2266. DISCOVERY_OUT("end", "------------");
  2267. }
  2268. #endif // HAVE_FLUIDSYNTH
  2269. // --------------------------------------------------------------------------------------------------------------------
  2270. // JSFX
  2271. #ifdef HAVE_YSFX
  2272. static void do_jsfx_check(const char* const filename, bool doInit)
  2273. {
  2274. const water::File file(filename);
  2275. ysfx_config_u config(ysfx_config_new());
  2276. ysfx_register_builtin_audio_formats(config.get());
  2277. ysfx_guess_file_roots(config.get(), filename);
  2278. ysfx_set_log_reporter(config.get(), &CarlaJsfxLogging::logErrorsOnly);
  2279. ysfx_u effect(ysfx_new(config.get()));
  2280. uint hints = 0;
  2281. // do not attempt to compile it, because the import path is not known
  2282. (void)doInit;
  2283. if (! ysfx_load_file(effect.get(), filename, 0))
  2284. {
  2285. DISCOVERY_OUT("error", "Cannot read the JSFX header");
  2286. return;
  2287. }
  2288. const char* const name = ysfx_get_name(effect.get());
  2289. // author and category are extracted from the pseudo-tags
  2290. const char* const author = ysfx_get_author(effect.get());
  2291. const CB::PluginCategory category = CarlaJsfxCategories::getFromEffect(effect.get());
  2292. const uint32_t audioIns = ysfx_get_num_inputs(effect.get());
  2293. const uint32_t audioOuts = ysfx_get_num_outputs(effect.get());
  2294. const uint32_t midiIns = 1;
  2295. const uint32_t midiOuts = 1;
  2296. uint32_t parameters = 0;
  2297. for (uint32_t sliderIndex = 0; sliderIndex < ysfx_max_sliders; ++sliderIndex)
  2298. {
  2299. if (ysfx_slider_exists(effect.get(), sliderIndex))
  2300. ++parameters;
  2301. }
  2302. DISCOVERY_OUT("init", "------------");
  2303. DISCOVERY_OUT("build", BINARY_NATIVE);
  2304. DISCOVERY_OUT("hints", hints);
  2305. DISCOVERY_OUT("category", getPluginCategoryAsString(category));
  2306. DISCOVERY_OUT("name", name);
  2307. DISCOVERY_OUT("maker", author);
  2308. DISCOVERY_OUT("label", filename);
  2309. DISCOVERY_OUT("audio.ins", audioIns);
  2310. DISCOVERY_OUT("audio.outs", audioOuts);
  2311. DISCOVERY_OUT("midi.ins", midiIns);
  2312. DISCOVERY_OUT("midi.outs", midiOuts);
  2313. DISCOVERY_OUT("parameters.ins", parameters);
  2314. DISCOVERY_OUT("end", "------------");
  2315. }
  2316. #endif // HAVE_YSFX
  2317. // --------------------------------------------------------------------------------------------------------------------
  2318. // main entry point
  2319. int main(int argc, const char* argv[])
  2320. {
  2321. if (argc != 3 && argc != 7)
  2322. {
  2323. carla_stdout("usage: %s <type> </path/to/plugin>", argv[0]);
  2324. return 1;
  2325. }
  2326. const char* const stype = argv[1];
  2327. const char* const filename = argv[2];
  2328. const PluginType type = getPluginTypeFromString(stype);
  2329. CarlaString filenameCheck(filename);
  2330. filenameCheck.toLower();
  2331. bool openLib;
  2332. lib_t handle = nullptr;
  2333. switch (type)
  2334. {
  2335. case PLUGIN_LADSPA:
  2336. case PLUGIN_DSSI:
  2337. // only available as single binary
  2338. openLib = true;
  2339. break;
  2340. case PLUGIN_VST2:
  2341. case PLUGIN_CLAP:
  2342. #ifdef CARLA_OS_MAC
  2343. // bundle on macOS
  2344. openLib = false;
  2345. #else
  2346. // single binary on all else
  2347. openLib = true;
  2348. #endif
  2349. break;
  2350. case PLUGIN_VST3:
  2351. #if defined(CARLA_OS_WIN)
  2352. // either file or bundle on Windows
  2353. openLib = water::File(filename).existsAsFile();
  2354. #else
  2355. // bundle on all else
  2356. openLib = false;
  2357. #endif
  2358. break;
  2359. default:
  2360. openLib = false;
  2361. break;
  2362. }
  2363. if (type != PLUGIN_SF2 && filenameCheck.contains("fluidsynth", true))
  2364. {
  2365. DISCOVERY_OUT("info", "skipping fluidsynth based plugin");
  2366. return 0;
  2367. }
  2368. // ----------------------------------------------------------------------------------------------------------------
  2369. // Initialize OS features
  2370. // we want stuff in English so we can parse error messages
  2371. ::setlocale(LC_ALL, "C");
  2372. #ifndef CARLA_OS_WIN
  2373. carla_setenv("LC_ALL", "C");
  2374. #endif
  2375. #ifdef CARLA_OS_WIN
  2376. // init win32 stuff that plugins might use
  2377. OleInitialize(nullptr);
  2378. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
  2379. #ifndef __WINPTHREADS_VERSION
  2380. // (non-portable) initialization of statically linked pthread library
  2381. pthread_win32_process_attach_np();
  2382. pthread_win32_thread_attach_np();
  2383. #endif
  2384. // do not show error message box on Windows
  2385. SetErrorMode(SEM_NOGPFAULTERRORBOX);
  2386. SetUnhandledExceptionFilter(winExceptionFilter);
  2387. #endif
  2388. // ----------------------------------------------------------------------------------------------------------------
  2389. // Initialize pipe
  2390. if (argc == 7)
  2391. {
  2392. gPipe = new DiscoveryPipe;
  2393. if (! gPipe->initPipeClient(argv))
  2394. return 1;
  2395. }
  2396. // ----------------------------------------------------------------------------------------------------------------
  2397. if (openLib)
  2398. {
  2399. handle = lib_open(filename);
  2400. if (handle == nullptr)
  2401. {
  2402. print_lib_error(filename);
  2403. gPipe = nullptr;
  2404. return 1;
  2405. }
  2406. }
  2407. // never do init for dssi-vst, takes too long and it's crashy
  2408. bool doInit = ! filenameCheck.contains("dssi-vst", true);
  2409. if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") != nullptr)
  2410. doInit = false;
  2411. // ----------------------------------------------------------------------------------------------------------------
  2412. if (doInit && openLib && handle != nullptr)
  2413. {
  2414. // test fast loading & unloading DLL without initializing the plugin(s)
  2415. if (! lib_close(handle))
  2416. {
  2417. print_lib_error(filename);
  2418. gPipe = nullptr;
  2419. return 1;
  2420. }
  2421. handle = lib_open(filename);
  2422. if (handle == nullptr)
  2423. {
  2424. print_lib_error(filename);
  2425. gPipe = nullptr;
  2426. return 1;
  2427. }
  2428. }
  2429. #ifndef BUILD_BRIDGE
  2430. if (std::strcmp(filename, ":all") == 0)
  2431. {
  2432. do_cached_check(type);
  2433. gPipe = nullptr;
  2434. return 0;
  2435. }
  2436. #endif
  2437. #ifdef CARLA_OS_MAC
  2438. // Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
  2439. switch (type)
  2440. {
  2441. case PLUGIN_LADSPA:
  2442. case PLUGIN_DSSI:
  2443. case PLUGIN_VST2:
  2444. case PLUGIN_VST3:
  2445. case PLUGIN_AU:
  2446. case PLUGIN_CLAP:
  2447. removeFileFromQuarantine(filename);
  2448. break;
  2449. default:
  2450. break;
  2451. }
  2452. #endif
  2453. // some macOS plugins have not been yet ported to arm64, re-run them in x86_64 mode if discovery fails
  2454. bool retryAsX64lugin = false;
  2455. switch (type)
  2456. {
  2457. case PLUGIN_LADSPA:
  2458. do_ladspa_check(handle, filename, doInit);
  2459. break;
  2460. case PLUGIN_DSSI:
  2461. do_dssi_check(handle, filename, doInit);
  2462. break;
  2463. #ifndef BUILD_BRIDGE
  2464. case PLUGIN_LV2:
  2465. do_lv2_check(filename, doInit);
  2466. break;
  2467. #endif
  2468. case PLUGIN_VST2:
  2469. retryAsX64lugin = do_vst2_check(handle, filename, doInit);
  2470. break;
  2471. case PLUGIN_VST3:
  2472. retryAsX64lugin = do_vst3_check(handle, filename, doInit);
  2473. break;
  2474. case PLUGIN_AU:
  2475. #ifdef CARLA_OS_MAC
  2476. retryAsX64lugin = do_au_check(filename, doInit);
  2477. #else
  2478. DISCOVERY_OUT("error", "AU support not available");
  2479. #endif
  2480. break;
  2481. case PLUGIN_JSFX:
  2482. #ifdef HAVE_YSFX
  2483. do_jsfx_check(filename, doInit);
  2484. #else
  2485. DISCOVERY_OUT("error", "JSFX support not available");
  2486. #endif
  2487. break;
  2488. case PLUGIN_CLAP:
  2489. retryAsX64lugin = do_clap_check(handle, filename, doInit);
  2490. break;
  2491. case PLUGIN_DLS:
  2492. case PLUGIN_GIG:
  2493. case PLUGIN_SF2:
  2494. #ifdef HAVE_FLUIDSYNTH
  2495. do_fluidsynth_check(filename, type, doInit);
  2496. #else
  2497. DISCOVERY_OUT("error", "SF2 support not available");
  2498. #endif
  2499. break;
  2500. default:
  2501. break;
  2502. }
  2503. if (openLib && handle != nullptr)
  2504. lib_close(handle);
  2505. if (retryAsX64lugin)
  2506. {
  2507. #if defined(CARLA_OS_MAC) && defined(__aarch64__)
  2508. DISCOVERY_OUT("warning", "No plugins found while scanning in arm64 mode, will try x86_64 now");
  2509. cpu_type_t pref = CPU_TYPE_X86_64;
  2510. pid_t pid = -1;
  2511. posix_spawnattr_t attr;
  2512. posix_spawnattr_init(&attr);
  2513. CARLA_SAFE_ASSERT_RETURN(posix_spawnattr_setbinpref_np(&attr, 1, &pref, nullptr) == 0, 1);
  2514. CARLA_SAFE_ASSERT_RETURN(posix_spawn(&pid, argv[0], nullptr, &attr, (char* const*)argv, nullptr) == 0, 1);
  2515. posix_spawnattr_destroy(&attr);
  2516. if (pid > 0)
  2517. {
  2518. int status;
  2519. waitpid(pid, &status, 0);
  2520. }
  2521. #endif
  2522. }
  2523. gPipe = nullptr;
  2524. // ----------------------------------------------------------------------------------------------------------------
  2525. #ifdef CARLA_OS_WIN
  2526. #ifndef __WINPTHREADS_VERSION
  2527. pthread_win32_thread_detach_np();
  2528. pthread_win32_process_detach_np();
  2529. #endif
  2530. CoUninitialize();
  2531. OleUninitialize();
  2532. #endif
  2533. return 0;
  2534. }
  2535. // --------------------------------------------------------------------------------------------------------------------