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.

1982 lines
61KB

  1. /*
  2. * Carla Plugin discovery
  3. * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #include "CarlaBackendUtils.hpp"
  18. #include "CarlaLibUtils.hpp"
  19. #include "CarlaMathUtils.hpp"
  20. #include "CarlaMIDI.h"
  21. #include "LinkedList.hpp"
  22. #ifdef BUILD_BRIDGE
  23. # undef HAVE_FLUIDSYNTH
  24. #endif
  25. #ifdef USING_JUCE
  26. # if defined(__clang__)
  27. # pragma clang diagnostic push
  28. # pragma clang diagnostic ignored "-Wfloat-equal"
  29. # pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
  30. # elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  31. # pragma GCC diagnostic push
  32. # pragma GCC diagnostic ignored "-Wconversion"
  33. # pragma GCC diagnostic ignored "-Wdouble-promotion"
  34. # pragma GCC diagnostic ignored "-Weffc++"
  35. # pragma GCC diagnostic ignored "-Wfloat-equal"
  36. # endif
  37. # include "../backend/utils/JUCE.cpp"
  38. # include "AppConfig.h"
  39. # include "juce_audio_processors/juce_audio_processors.h"
  40. # if JUCE_PLUGINHOST_VST
  41. # define USING_JUCE_FOR_VST2
  42. # endif
  43. # if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
  44. # pragma GCC diagnostic pop
  45. # endif
  46. #endif
  47. #include "CarlaLadspaUtils.hpp"
  48. #include "CarlaLv2Utils.hpp"
  49. #ifndef USING_JUCE_FOR_VST2
  50. # include "CarlaVst2Utils.hpp"
  51. #endif
  52. #ifdef CARLA_OS_MAC
  53. # define Component CocoaComponent
  54. # define MemoryBlock CocoaMemoryBlock
  55. # define Point CocoaPoint
  56. # import <Foundation/Foundation.h>
  57. # undef Component
  58. # undef MemoryBlock
  59. # undef Point
  60. # include "CarlaMacUtils.cpp"
  61. # include <spawn.h>
  62. # if defined(USING_JUCE) && defined(__aarch64__)
  63. # include <spawn.h>
  64. # endif
  65. #endif
  66. #ifdef CARLA_OS_WIN
  67. # include <pthread.h>
  68. # include <objbase.h>
  69. #endif
  70. #ifdef HAVE_FLUIDSYNTH
  71. # include <fluidsynth.h>
  72. #endif
  73. #include <iostream>
  74. #include "water/files/File.h"
  75. #ifndef BUILD_BRIDGE
  76. # include "water/text/StringArray.h"
  77. # include "CarlaDssiUtils.cpp"
  78. # include "CarlaJsfxUtils.hpp"
  79. # include "../backend/utils/CachedPlugins.cpp"
  80. #else
  81. # include "CarlaDssiUtils.hpp"
  82. #endif
  83. #define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl;
  84. using water::CharPointer_UTF8;
  85. using water::File;
  86. using water::StringArray;
  87. CARLA_BACKEND_USE_NAMESPACE
  88. // -------------------------------------------------------------------------------------------------------------------
  89. // Dummy values to test plugins with
  90. static const uint32_t kBufferSize = 512;
  91. static const double kSampleRate = 44100.0;
  92. static const int32_t kSampleRatei = 44100;
  93. static const float kSampleRatef = 44100.0f;
  94. // -------------------------------------------------------------------------------------------------------------------
  95. // Don't print ELF/EXE related errors since discovery can find multi-architecture binaries
  96. static void print_lib_error(const char* const filename)
  97. {
  98. const char* const error(lib_error(filename));
  99. if (error != nullptr &&
  100. std::strstr(error, "wrong ELF class") == nullptr &&
  101. std::strstr(error, "invalid ELF header") == nullptr &&
  102. std::strstr(error, "Bad EXE format") == nullptr &&
  103. std::strstr(error, "no suitable image found") == nullptr &&
  104. std::strstr(error, "not a valid Win32 application") == nullptr)
  105. {
  106. DISCOVERY_OUT("error", error);
  107. }
  108. }
  109. // ------------------------------ Plugin Checks -----------------------------
  110. #ifndef BUILD_BRIDGE
  111. static void print_cached_plugin(const CarlaCachedPluginInfo* const pinfo)
  112. {
  113. if (! pinfo->valid)
  114. return;
  115. DISCOVERY_OUT("init", "-----------");
  116. DISCOVERY_OUT("build", BINARY_NATIVE);
  117. DISCOVERY_OUT("hints", pinfo->hints);
  118. DISCOVERY_OUT("category", getPluginCategoryAsString(pinfo->category));
  119. DISCOVERY_OUT("name", pinfo->name);
  120. DISCOVERY_OUT("maker", pinfo->maker);
  121. DISCOVERY_OUT("label", pinfo->label);
  122. DISCOVERY_OUT("audio.ins", pinfo->audioIns);
  123. DISCOVERY_OUT("audio.outs", pinfo->audioOuts);
  124. DISCOVERY_OUT("cv.ins", pinfo->cvIns);
  125. DISCOVERY_OUT("cv.outs", pinfo->cvOuts);
  126. DISCOVERY_OUT("midi.ins", pinfo->midiIns);
  127. DISCOVERY_OUT("midi.outs", pinfo->midiOuts);
  128. DISCOVERY_OUT("parameters.ins", pinfo->parameterIns);
  129. DISCOVERY_OUT("parameters.outs", pinfo->parameterOuts);
  130. DISCOVERY_OUT("end", "------------");
  131. }
  132. static void do_cached_check(const PluginType type)
  133. {
  134. const char* plugPath;
  135. switch (type)
  136. {
  137. case PLUGIN_LV2:
  138. plugPath = std::getenv("LV2_PATH");
  139. break;
  140. case PLUGIN_SFZ:
  141. plugPath = std::getenv("SFZ_PATH");
  142. break;
  143. default:
  144. plugPath = nullptr;
  145. break;
  146. }
  147. # ifdef USING_JUCE
  148. if (type == PLUGIN_AU)
  149. carla_juce_init();
  150. # endif
  151. const uint count = carla_get_cached_plugin_count(type, plugPath);
  152. for (uint i=0; i<count; ++i)
  153. {
  154. const CarlaCachedPluginInfo* pinfo(carla_get_cached_plugin_info(type, i));
  155. CARLA_SAFE_ASSERT_CONTINUE(pinfo != nullptr);
  156. print_cached_plugin(pinfo);
  157. }
  158. # ifdef USING_JUCE
  159. if (type == PLUGIN_AU)
  160. carla_juce_cleanup();
  161. # endif
  162. }
  163. #endif
  164. static void do_ladspa_check(lib_t& libHandle, const char* const filename, const bool doInit)
  165. {
  166. LADSPA_Descriptor_Function descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  167. if (descFn == nullptr)
  168. {
  169. DISCOVERY_OUT("error", "Not a LADSPA plugin");
  170. return;
  171. }
  172. const LADSPA_Descriptor* descriptor;
  173. {
  174. descriptor = descFn(0);
  175. if (descriptor == nullptr)
  176. {
  177. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  178. return;
  179. }
  180. if (doInit && descriptor->instantiate != nullptr && descriptor->cleanup != nullptr)
  181. {
  182. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  183. if (handle == nullptr)
  184. {
  185. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  186. return;
  187. }
  188. descriptor->cleanup(handle);
  189. lib_close(libHandle);
  190. libHandle = lib_open(filename);
  191. if (libHandle == nullptr)
  192. {
  193. print_lib_error(filename);
  194. return;
  195. }
  196. descFn = lib_symbol<LADSPA_Descriptor_Function>(libHandle, "ladspa_descriptor");
  197. if (descFn == nullptr)
  198. {
  199. DISCOVERY_OUT("error", "Not a LADSPA plugin (#2)");
  200. return;
  201. }
  202. }
  203. }
  204. unsigned long i = 0;
  205. while ((descriptor = descFn(i++)) != nullptr)
  206. {
  207. if (descriptor->instantiate == nullptr)
  208. {
  209. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no instantiate()");
  210. continue;
  211. }
  212. if (descriptor->cleanup == nullptr)
  213. {
  214. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no cleanup()");
  215. continue;
  216. }
  217. if (descriptor->run == nullptr)
  218. {
  219. DISCOVERY_OUT("error", "Plugin '" << descriptor->Name << "' has no run()");
  220. continue;
  221. }
  222. if (! LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  223. {
  224. DISCOVERY_OUT("warning", "Plugin '" << descriptor->Name << "' is not hard real-time capable");
  225. }
  226. uint hints = 0x0;
  227. uint audioIns = 0;
  228. uint audioOuts = 0;
  229. uint audioTotal = 0;
  230. uint parametersIns = 0;
  231. uint parametersOuts = 0;
  232. uint parametersTotal = 0;
  233. if (LADSPA_IS_HARD_RT_CAPABLE(descriptor->Properties))
  234. hints |= PLUGIN_IS_RTSAFE;
  235. for (unsigned long j=0; j < descriptor->PortCount; ++j)
  236. {
  237. CARLA_ASSERT(descriptor->PortNames[j] != nullptr);
  238. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  239. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  240. {
  241. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  242. audioIns += 1;
  243. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  244. audioOuts += 1;
  245. audioTotal += 1;
  246. }
  247. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  248. {
  249. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  250. parametersIns += 1;
  251. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(descriptor->PortNames[j], "latency") != 0 && std::strcmp(descriptor->PortNames[j], "_latency") != 0)
  252. parametersOuts += 1;
  253. parametersTotal += 1;
  254. }
  255. }
  256. if (doInit)
  257. {
  258. // -----------------------------------------------------------------------
  259. // start crash-free plugin test
  260. LADSPA_Handle handle = descriptor->instantiate(descriptor, kSampleRatei);
  261. if (handle == nullptr)
  262. {
  263. DISCOVERY_OUT("error", "Failed to init LADSPA plugin");
  264. continue;
  265. }
  266. // Test quick init and cleanup
  267. descriptor->cleanup(handle);
  268. handle = descriptor->instantiate(descriptor, kSampleRatei);
  269. if (handle == nullptr)
  270. {
  271. DISCOVERY_OUT("error", "Failed to init LADSPA plugin (#2)");
  272. continue;
  273. }
  274. LADSPA_Data bufferAudio[kBufferSize][audioTotal];
  275. LADSPA_Data bufferParams[parametersTotal];
  276. LADSPA_Data min, max, def;
  277. for (unsigned long j=0, iA=0, iC=0; j < descriptor->PortCount; ++j)
  278. {
  279. const LADSPA_PortDescriptor portDescriptor = descriptor->PortDescriptors[j];
  280. const LADSPA_PortRangeHint portRangeHints = descriptor->PortRangeHints[j];
  281. const char* const portName = descriptor->PortNames[j];
  282. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  283. {
  284. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  285. descriptor->connect_port(handle, j, bufferAudio[iA++]);
  286. }
  287. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  288. {
  289. // min value
  290. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  291. min = portRangeHints.LowerBound;
  292. else
  293. min = 0.0f;
  294. // max value
  295. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  296. max = portRangeHints.UpperBound;
  297. else
  298. max = 1.0f;
  299. if (min > max)
  300. {
  301. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  302. max = min + 0.1f;
  303. }
  304. else if (carla_isEqual(min, max))
  305. {
  306. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  307. max = min + 0.1f;
  308. }
  309. // default value
  310. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  311. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  312. {
  313. min *= kSampleRatef;
  314. max *= kSampleRatef;
  315. def *= kSampleRatef;
  316. }
  317. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  318. {
  319. // latency parameter
  320. def = 0.0f;
  321. }
  322. else
  323. {
  324. if (def < min)
  325. def = min;
  326. else if (def > max)
  327. def = max;
  328. }
  329. bufferParams[iC] = def;
  330. descriptor->connect_port(handle, j, &bufferParams[iC++]);
  331. }
  332. }
  333. if (descriptor->activate != nullptr)
  334. descriptor->activate(handle);
  335. descriptor->run(handle, kBufferSize);
  336. if (descriptor->deactivate != nullptr)
  337. descriptor->deactivate(handle);
  338. descriptor->cleanup(handle);
  339. // end crash-free plugin test
  340. // -----------------------------------------------------------------------
  341. }
  342. DISCOVERY_OUT("init", "-----------");
  343. DISCOVERY_OUT("build", BINARY_NATIVE);
  344. DISCOVERY_OUT("hints", hints);
  345. DISCOVERY_OUT("category", getPluginCategoryAsString(getPluginCategoryFromName(descriptor->Name)));
  346. DISCOVERY_OUT("name", descriptor->Name);
  347. DISCOVERY_OUT("label", descriptor->Label);
  348. DISCOVERY_OUT("maker", descriptor->Maker);
  349. DISCOVERY_OUT("uniqueId", descriptor->UniqueID);
  350. DISCOVERY_OUT("audio.ins", audioIns);
  351. DISCOVERY_OUT("audio.outs", audioOuts);
  352. DISCOVERY_OUT("parameters.ins", parametersIns);
  353. DISCOVERY_OUT("parameters.outs", parametersOuts);
  354. DISCOVERY_OUT("end", "------------");
  355. }
  356. }
  357. static void do_dssi_check(lib_t& libHandle, const char* const filename, const bool doInit)
  358. {
  359. DSSI_Descriptor_Function descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  360. if (descFn == nullptr)
  361. {
  362. DISCOVERY_OUT("error", "Not a DSSI plugin");
  363. return;
  364. }
  365. const DSSI_Descriptor* descriptor;
  366. {
  367. descriptor = descFn(0);
  368. if (descriptor == nullptr)
  369. {
  370. DISCOVERY_OUT("error", "Binary doesn't contain any plugins");
  371. return;
  372. }
  373. const LADSPA_Descriptor* const ldescriptor(descriptor->LADSPA_Plugin);
  374. if (ldescriptor == nullptr)
  375. {
  376. DISCOVERY_OUT("error", "DSSI plugin doesn't provide the LADSPA interface");
  377. return;
  378. }
  379. if (doInit && ldescriptor->instantiate != nullptr && ldescriptor->cleanup != nullptr)
  380. {
  381. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  382. if (handle == nullptr)
  383. {
  384. DISCOVERY_OUT("error", "Failed to init first LADSPA plugin");
  385. return;
  386. }
  387. ldescriptor->cleanup(handle);
  388. lib_close(libHandle);
  389. libHandle = lib_open(filename);
  390. if (libHandle == nullptr)
  391. {
  392. print_lib_error(filename);
  393. return;
  394. }
  395. descFn = lib_symbol<DSSI_Descriptor_Function>(libHandle, "dssi_descriptor");
  396. if (descFn == nullptr)
  397. {
  398. DISCOVERY_OUT("error", "Not a DSSI plugin (#2)");
  399. return;
  400. }
  401. }
  402. }
  403. unsigned long i = 0;
  404. while ((descriptor = descFn(i++)) != nullptr)
  405. {
  406. const LADSPA_Descriptor* const ldescriptor = descriptor->LADSPA_Plugin;
  407. if (ldescriptor == nullptr)
  408. {
  409. DISCOVERY_OUT("error", "Plugin has no LADSPA interface");
  410. continue;
  411. }
  412. if (descriptor->DSSI_API_Version != DSSI_VERSION_MAJOR)
  413. {
  414. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' uses an unsupported DSSI spec version " << descriptor->DSSI_API_Version);
  415. continue;
  416. }
  417. if (ldescriptor->instantiate == nullptr)
  418. {
  419. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no instantiate()");
  420. continue;
  421. }
  422. if (ldescriptor->cleanup == nullptr)
  423. {
  424. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no cleanup()");
  425. continue;
  426. }
  427. if (ldescriptor->run == nullptr && descriptor->run_synth == nullptr)
  428. {
  429. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' has no run() or run_synth()");
  430. continue;
  431. }
  432. if (descriptor->run_synth == nullptr && descriptor->run_multiple_synths != nullptr)
  433. {
  434. DISCOVERY_OUT("error", "Plugin '" << ldescriptor->Name << "' requires run_multiple_synths which is not supported");
  435. continue;
  436. }
  437. if (! LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  438. {
  439. DISCOVERY_OUT("warning", "Plugin '" << ldescriptor->Name << "' is not hard real-time capable");
  440. }
  441. uint hints = 0x0;
  442. uint audioIns = 0;
  443. uint audioOuts = 0;
  444. uint audioTotal = 0;
  445. uint midiIns = 0;
  446. uint parametersIns = 0;
  447. uint parametersOuts = 0;
  448. uint parametersTotal = 0;
  449. if (LADSPA_IS_HARD_RT_CAPABLE(ldescriptor->Properties))
  450. hints |= PLUGIN_IS_RTSAFE;
  451. for (unsigned long j=0; j < ldescriptor->PortCount; ++j)
  452. {
  453. CARLA_ASSERT(ldescriptor->PortNames[j] != nullptr);
  454. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  455. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  456. {
  457. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  458. audioIns += 1;
  459. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor))
  460. audioOuts += 1;
  461. audioTotal += 1;
  462. }
  463. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  464. {
  465. if (LADSPA_IS_PORT_INPUT(portDescriptor))
  466. parametersIns += 1;
  467. else if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && std::strcmp(ldescriptor->PortNames[j], "latency") != 0 && std::strcmp(ldescriptor->PortNames[j], "_latency") != 0)
  468. parametersOuts += 1;
  469. parametersTotal += 1;
  470. }
  471. }
  472. if (descriptor->run_synth != nullptr)
  473. midiIns = 1;
  474. if (midiIns > 0 && audioIns == 0 && audioOuts > 0)
  475. hints |= PLUGIN_IS_SYNTH;
  476. #ifndef BUILD_BRIDGE
  477. if (const char* const ui = find_dssi_ui(filename, ldescriptor->Label))
  478. {
  479. hints |= PLUGIN_HAS_CUSTOM_UI;
  480. delete[] ui;
  481. }
  482. #endif
  483. if (doInit)
  484. {
  485. // -----------------------------------------------------------------------
  486. // start crash-free plugin test
  487. LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  488. if (handle == nullptr)
  489. {
  490. DISCOVERY_OUT("error", "Failed to init DSSI plugin");
  491. continue;
  492. }
  493. // Test quick init and cleanup
  494. ldescriptor->cleanup(handle);
  495. handle = ldescriptor->instantiate(ldescriptor, kSampleRatei);
  496. if (handle == nullptr)
  497. {
  498. DISCOVERY_OUT("error", "Failed to init DSSI plugin (#2)");
  499. continue;
  500. }
  501. LADSPA_Data bufferAudio[kBufferSize][audioTotal];
  502. LADSPA_Data bufferParams[parametersTotal];
  503. LADSPA_Data min, max, def;
  504. for (unsigned long j=0, iA=0, iC=0; j < ldescriptor->PortCount; ++j)
  505. {
  506. const LADSPA_PortDescriptor portDescriptor = ldescriptor->PortDescriptors[j];
  507. const LADSPA_PortRangeHint portRangeHints = ldescriptor->PortRangeHints[j];
  508. const char* const portName = ldescriptor->PortNames[j];
  509. if (LADSPA_IS_PORT_AUDIO(portDescriptor))
  510. {
  511. carla_zeroFloats(bufferAudio[iA], kBufferSize);
  512. ldescriptor->connect_port(handle, j, bufferAudio[iA++]);
  513. }
  514. else if (LADSPA_IS_PORT_CONTROL(portDescriptor))
  515. {
  516. // min value
  517. if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
  518. min = portRangeHints.LowerBound;
  519. else
  520. min = 0.0f;
  521. // max value
  522. if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
  523. max = portRangeHints.UpperBound;
  524. else
  525. max = 1.0f;
  526. if (min > max)
  527. {
  528. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: min > max");
  529. max = min + 0.1f;
  530. }
  531. else if (carla_isEqual(min, max))
  532. {
  533. DISCOVERY_OUT("warning", "Parameter '" << portName << "' is broken: max == min");
  534. max = min + 0.1f;
  535. }
  536. // default value
  537. def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
  538. if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
  539. {
  540. min *= kSampleRatef;
  541. max *= kSampleRatef;
  542. def *= kSampleRatef;
  543. }
  544. if (LADSPA_IS_PORT_OUTPUT(portDescriptor) && (std::strcmp(portName, "latency") == 0 || std::strcmp(portName, "_latency") == 0))
  545. {
  546. // latency parameter
  547. def = 0.0f;
  548. }
  549. else
  550. {
  551. if (def < min)
  552. def = min;
  553. else if (def > max)
  554. def = max;
  555. }
  556. bufferParams[iC] = def;
  557. ldescriptor->connect_port(handle, j, &bufferParams[iC++]);
  558. }
  559. }
  560. // select first midi-program if available
  561. if (descriptor->get_program != nullptr && descriptor->select_program != nullptr)
  562. {
  563. if (const DSSI_Program_Descriptor* const pDesc = descriptor->get_program(handle, 0))
  564. descriptor->select_program(handle, pDesc->Bank, pDesc->Program);
  565. }
  566. if (ldescriptor->activate != nullptr)
  567. ldescriptor->activate(handle);
  568. if (descriptor->run_synth != nullptr)
  569. {
  570. snd_seq_event_t midiEvents[2];
  571. carla_zeroStructs(midiEvents, 2);
  572. const unsigned long midiEventCount = 2;
  573. midiEvents[0].type = SND_SEQ_EVENT_NOTEON;
  574. midiEvents[0].data.note.note = 64;
  575. midiEvents[0].data.note.velocity = 100;
  576. midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF;
  577. midiEvents[1].data.note.note = 64;
  578. midiEvents[1].data.note.velocity = 0;
  579. midiEvents[1].time.tick = kBufferSize/2;
  580. descriptor->run_synth(handle, kBufferSize, midiEvents, midiEventCount);
  581. }
  582. else
  583. ldescriptor->run(handle, kBufferSize);
  584. if (ldescriptor->deactivate != nullptr)
  585. ldescriptor->deactivate(handle);
  586. ldescriptor->cleanup(handle);
  587. // end crash-free plugin test
  588. // -----------------------------------------------------------------------
  589. }
  590. DISCOVERY_OUT("init", "-----------");
  591. DISCOVERY_OUT("build", BINARY_NATIVE);
  592. DISCOVERY_OUT("category", ((hints & PLUGIN_IS_SYNTH)
  593. ? "synth"
  594. : getPluginCategoryAsString(getPluginCategoryFromName(ldescriptor->Name))));
  595. DISCOVERY_OUT("hints", hints);
  596. DISCOVERY_OUT("name", ldescriptor->Name);
  597. DISCOVERY_OUT("label", ldescriptor->Label);
  598. DISCOVERY_OUT("maker", ldescriptor->Maker);
  599. DISCOVERY_OUT("uniqueId", ldescriptor->UniqueID);
  600. DISCOVERY_OUT("audio.ins", audioIns);
  601. DISCOVERY_OUT("audio.outs", audioOuts);
  602. DISCOVERY_OUT("midi.ins", midiIns);
  603. DISCOVERY_OUT("parameters.ins", parametersIns);
  604. DISCOVERY_OUT("parameters.outs", parametersOuts);
  605. DISCOVERY_OUT("end", "------------");
  606. }
  607. }
  608. #ifndef BUILD_BRIDGE
  609. static void do_lv2_check(const char* const bundle, const bool doInit)
  610. {
  611. Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
  612. Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, bundle));
  613. CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(),);
  614. CarlaString sBundle(bundleNode.as_uri());
  615. if (! sBundle.endsWith("/"))
  616. sBundle += "/";
  617. // Load bundle
  618. lv2World.load_bundle(sBundle);
  619. // Load plugins in this bundle
  620. const Lilv::Plugins lilvPlugins(lv2World.get_all_plugins());
  621. // Get all plugin URIs in this bundle
  622. water::StringArray URIs;
  623. LILV_FOREACH(plugins, it, lilvPlugins)
  624. {
  625. Lilv::Plugin lilvPlugin(lilv_plugins_get(lilvPlugins, it));
  626. if (const char* const uri = lilvPlugin.get_uri().as_string())
  627. URIs.addIfNotAlreadyThere(water::String(uri));
  628. }
  629. if (URIs.size() == 0)
  630. {
  631. DISCOVERY_OUT("warning", "LV2 Bundle doesn't provide any plugins");
  632. return;
  633. }
  634. // Get & check every plugin-instance
  635. for (int i=0, count=URIs.size(); i < count; ++i)
  636. {
  637. const char* const URI = URIs[i].toRawUTF8();
  638. CarlaScopedPointer<const LV2_RDF_Descriptor> rdfDescriptor(lv2_rdf_new(URI, false));
  639. if (rdfDescriptor == nullptr || rdfDescriptor->URI == nullptr)
  640. {
  641. DISCOVERY_OUT("error", "Failed to find LV2 plugin '" << URI << "'");
  642. continue;
  643. }
  644. if (doInit)
  645. {
  646. // test if lib is loadable, twice
  647. const lib_t libHandle1 = lib_open(rdfDescriptor->Binary);
  648. if (libHandle1 == nullptr)
  649. {
  650. print_lib_error(rdfDescriptor->Binary);
  651. delete rdfDescriptor;
  652. continue;
  653. }
  654. lib_close(libHandle1);
  655. const lib_t libHandle2 = lib_open(rdfDescriptor->Binary);
  656. if (libHandle2 == nullptr)
  657. {
  658. print_lib_error(rdfDescriptor->Binary);
  659. delete rdfDescriptor;
  660. continue;
  661. }
  662. lib_close(libHandle2);
  663. }
  664. const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(URI));
  665. CARLA_SAFE_ASSERT_CONTINUE(cPlugin != nullptr);
  666. Lilv::Plugin lilvPlugin(cPlugin);
  667. CARLA_SAFE_ASSERT_CONTINUE(lilvPlugin.get_uri().is_uri());
  668. print_cached_plugin(get_cached_plugin_lv2(lv2World, lilvPlugin));
  669. }
  670. }
  671. #endif
  672. #ifndef USING_JUCE_FOR_VST2
  673. // -------------------------------------------------------------------------------------------------------------------
  674. // VST stuff
  675. // Check if plugin is currently processing
  676. static bool gVstIsProcessing = false;
  677. // Check if plugin needs idle
  678. static bool gVstNeedsIdle = false;
  679. // Check if plugin wants midi
  680. static bool gVstWantsMidi = false;
  681. // Check if plugin wants time
  682. static bool gVstWantsTime = false;
  683. // Current uniqueId for VST shell plugins
  684. static intptr_t gVstCurrentUniqueId = 0;
  685. // Supported Carla features
  686. static intptr_t vstHostCanDo(const char* const feature)
  687. {
  688. carla_debug("vstHostCanDo(\"%s\")", feature);
  689. if (std::strcmp(feature, "supplyIdle") == 0)
  690. return 1;
  691. if (std::strcmp(feature, "sendVstEvents") == 0)
  692. return 1;
  693. if (std::strcmp(feature, "sendVstMidiEvent") == 0)
  694. return 1;
  695. if (std::strcmp(feature, "sendVstMidiEventFlagIsRealtime") == 0)
  696. return 1;
  697. if (std::strcmp(feature, "sendVstTimeInfo") == 0)
  698. {
  699. gVstWantsTime = true;
  700. return 1;
  701. }
  702. if (std::strcmp(feature, "receiveVstEvents") == 0)
  703. return 1;
  704. if (std::strcmp(feature, "receiveVstMidiEvent") == 0)
  705. return 1;
  706. if (std::strcmp(feature, "receiveVstTimeInfo") == 0)
  707. return -1;
  708. if (std::strcmp(feature, "reportConnectionChanges") == 0)
  709. return -1;
  710. if (std::strcmp(feature, "acceptIOChanges") == 0)
  711. return 1;
  712. if (std::strcmp(feature, "sizeWindow") == 0)
  713. return 1;
  714. if (std::strcmp(feature, "offline") == 0)
  715. return -1;
  716. if (std::strcmp(feature, "openFileSelector") == 0)
  717. return -1;
  718. if (std::strcmp(feature, "closeFileSelector") == 0)
  719. return -1;
  720. if (std::strcmp(feature, "startStopProcess") == 0)
  721. return 1;
  722. if (std::strcmp(feature, "supportShell") == 0)
  723. return 1;
  724. if (std::strcmp(feature, "shellCategory") == 0)
  725. return 1;
  726. if (std::strcmp(feature, "NIMKPIVendorSpecificCallbacks") == 0)
  727. return -1;
  728. // non-official features found in some plugins:
  729. // "asyncProcessing"
  730. // "editFile"
  731. // unimplemented
  732. carla_stderr("vstHostCanDo(\"%s\") - unknown feature", feature);
  733. return 0;
  734. }
  735. // Host-side callback
  736. 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)
  737. {
  738. carla_debug("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
  739. effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
  740. static VstTimeInfo timeInfo;
  741. intptr_t ret = 0;
  742. switch (opcode)
  743. {
  744. case audioMasterAutomate:
  745. ret = 1;
  746. break;
  747. case audioMasterVersion:
  748. ret = kVstVersion;
  749. break;
  750. case audioMasterCurrentId:
  751. ret = gVstCurrentUniqueId;
  752. break;
  753. case DECLARE_VST_DEPRECATED(audioMasterWantMidi):
  754. if (gVstWantsMidi) { DISCOVERY_OUT("warning", "Plugin requested MIDI more than once"); }
  755. gVstWantsMidi = true;
  756. ret = 1;
  757. break;
  758. case audioMasterGetTime:
  759. if (! gVstIsProcessing) { DISCOVERY_OUT("warning", "Plugin requested timeInfo out of process"); }
  760. if (! gVstWantsTime) { DISCOVERY_OUT("warning", "Plugin requested timeInfo but didn't ask if host could do \"sendVstTimeInfo\""); }
  761. carla_zeroStruct(timeInfo);
  762. timeInfo.sampleRate = kSampleRate;
  763. // Tempo
  764. timeInfo.tempo = 120.0;
  765. timeInfo.flags |= kVstTempoValid;
  766. // Time Signature
  767. timeInfo.timeSigNumerator = 4;
  768. timeInfo.timeSigDenominator = 4;
  769. timeInfo.flags |= kVstTimeSigValid;
  770. ret = (intptr_t)&timeInfo;
  771. break;
  772. case DECLARE_VST_DEPRECATED(audioMasterTempoAt):
  773. ret = 120 * 10000;
  774. break;
  775. case DECLARE_VST_DEPRECATED(audioMasterGetNumAutomatableParameters):
  776. ret = carla_minPositive(effect->numParams, static_cast<int>(MAX_DEFAULT_PARAMETERS));
  777. break;
  778. case DECLARE_VST_DEPRECATED(audioMasterGetParameterQuantization):
  779. ret = 1; // full single float precision
  780. break;
  781. case DECLARE_VST_DEPRECATED(audioMasterNeedIdle):
  782. if (gVstNeedsIdle) { DISCOVERY_OUT("warning", "Plugin requested idle more than once"); }
  783. gVstNeedsIdle = true;
  784. ret = 1;
  785. break;
  786. case audioMasterGetSampleRate:
  787. ret = kSampleRatei;
  788. break;
  789. case audioMasterGetBlockSize:
  790. ret = kBufferSize;
  791. break;
  792. case DECLARE_VST_DEPRECATED(audioMasterWillReplaceOrAccumulate):
  793. ret = 1; // replace
  794. break;
  795. case audioMasterGetCurrentProcessLevel:
  796. ret = gVstIsProcessing ? kVstProcessLevelRealtime : kVstProcessLevelUser;
  797. break;
  798. case audioMasterGetAutomationState:
  799. ret = kVstAutomationOff;
  800. break;
  801. case audioMasterGetVendorString:
  802. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  803. std::strcpy((char*)ptr, "falkTX");
  804. ret = 1;
  805. break;
  806. case audioMasterGetProductString:
  807. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  808. std::strcpy((char*)ptr, "Carla-Discovery");
  809. ret = 1;
  810. break;
  811. case audioMasterGetVendorVersion:
  812. ret = CARLA_VERSION_HEX;
  813. break;
  814. case audioMasterCanDo:
  815. CARLA_SAFE_ASSERT_BREAK(ptr != nullptr);
  816. ret = vstHostCanDo((const char*)ptr);
  817. break;
  818. case audioMasterGetLanguage:
  819. ret = kVstLangEnglish;
  820. break;
  821. default:
  822. carla_stdout("vstHostCallback(%p, %i:%s, %i, " P_INTPTR ", %p, %f)",
  823. effect, opcode, vstMasterOpcode2str(opcode), index, value, ptr, static_cast<double>(opt));
  824. break;
  825. }
  826. return ret;
  827. }
  828. static void do_vst_check(lib_t& libHandle, const char* const filename, const bool doInit)
  829. {
  830. VST_Function vstFn = nullptr;
  831. #ifdef CARLA_OS_MAC
  832. CFBundleRef bundleRef = nullptr;
  833. CFBundleRefNum resFileId = 0;
  834. if (libHandle == nullptr)
  835. {
  836. const CFURLRef urlRef = CFURLCreateFromFileSystemRepresentation(0, (const UInt8*)filename, (CFIndex)strlen(filename), true);
  837. CARLA_SAFE_ASSERT_RETURN(urlRef != nullptr,);
  838. bundleRef = CFBundleCreate(kCFAllocatorDefault, urlRef);
  839. CFRelease(urlRef);
  840. CARLA_SAFE_ASSERT_RETURN(bundleRef != nullptr,);
  841. if (! CFBundleLoadExecutable(bundleRef))
  842. {
  843. CFRelease(bundleRef);
  844. DISCOVERY_OUT("error", "Failed to load VST bundle executable");
  845. return;
  846. }
  847. vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("main_macho"));
  848. if (vstFn == nullptr)
  849. vstFn = (VST_Function)CFBundleGetFunctionPointerForName(bundleRef, CFSTR("VSTPluginMain"));
  850. if (vstFn == nullptr)
  851. {
  852. CFBundleUnloadExecutable(bundleRef);
  853. CFRelease(bundleRef);
  854. DISCOVERY_OUT("error", "Not a VST plugin");
  855. return;
  856. }
  857. resFileId = CFBundleOpenBundleResourceMap(bundleRef);
  858. }
  859. else
  860. #endif
  861. {
  862. vstFn = lib_symbol<VST_Function>(libHandle, "VSTPluginMain");
  863. if (vstFn == nullptr)
  864. {
  865. vstFn = lib_symbol<VST_Function>(libHandle, "main");
  866. if (vstFn == nullptr)
  867. {
  868. DISCOVERY_OUT("error", "Not a VST plugin");
  869. return;
  870. }
  871. }
  872. }
  873. AEffect* effect = vstFn(vstHostCallback);
  874. if (effect == nullptr || effect->magic != kEffectMagic)
  875. {
  876. DISCOVERY_OUT("error", "Failed to init VST plugin, or VST magic failed");
  877. return;
  878. }
  879. if (effect->uniqueID == 0)
  880. {
  881. DISCOVERY_OUT("warning", "Plugin doesn't have an Unique ID when first loaded");
  882. }
  883. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  884. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  885. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  886. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  887. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  888. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  889. if (effect->numPrograms > 0)
  890. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  891. const bool isShell = (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f) == kPlugCategShell);
  892. if (effect->uniqueID == 0 && !isShell)
  893. {
  894. DISCOVERY_OUT("error", "Plugin doesn't have an Unique ID after being open");
  895. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  896. return;
  897. }
  898. gVstCurrentUniqueId = effect->uniqueID;
  899. char strBuf[STR_MAX+1];
  900. CarlaString cName;
  901. CarlaString cProduct;
  902. CarlaString cVendor;
  903. PluginCategory category;
  904. LinkedList<intptr_t> uniqueIds;
  905. if (isShell)
  906. {
  907. for (;;)
  908. {
  909. carla_zeroChars(strBuf, STR_MAX+1);
  910. gVstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, strBuf, 0.0f);
  911. if (gVstCurrentUniqueId == 0)
  912. break;
  913. uniqueIds.append(gVstCurrentUniqueId);
  914. }
  915. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  916. effect = nullptr;
  917. }
  918. else
  919. {
  920. uniqueIds.append(gVstCurrentUniqueId);
  921. }
  922. for (LinkedList<intptr_t>::Itenerator it = uniqueIds.begin2(); it.valid(); it.next())
  923. {
  924. gVstCurrentUniqueId = it.getValue(0);
  925. if (effect == nullptr)
  926. {
  927. effect = vstFn(vstHostCallback);
  928. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdentify), 0, 0, nullptr, 0.0f);
  929. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effSetBlockSizeAndSampleRate), 0, kBufferSize, nullptr, kSampleRatef);
  930. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, kSampleRatef);
  931. effect->dispatcher(effect, effSetBlockSize, 0, kBufferSize, nullptr, 0.0f);
  932. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  933. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  934. if (effect->numPrograms > 0)
  935. effect->dispatcher(effect, effSetProgram, 0, 0, nullptr, 0.0f);
  936. }
  937. // get name
  938. carla_zeroChars(strBuf, STR_MAX+1);
  939. if (effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f) == 1)
  940. cName = strBuf;
  941. else
  942. cName.clear();
  943. // get product
  944. carla_zeroChars(strBuf, STR_MAX+1);
  945. if (effect->dispatcher(effect, effGetProductString, 0, 0, strBuf, 0.0f) == 1)
  946. cProduct = strBuf;
  947. else
  948. cProduct.clear();
  949. // get vendor
  950. carla_zeroChars(strBuf, STR_MAX+1);
  951. if (effect->dispatcher(effect, effGetVendorString, 0, 0, strBuf, 0.0f) == 1)
  952. cVendor = strBuf;
  953. else
  954. cVendor.clear();
  955. // get category
  956. switch (effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f))
  957. {
  958. case kPlugCategSynth:
  959. category = PLUGIN_CATEGORY_SYNTH;
  960. break;
  961. case kPlugCategAnalysis:
  962. category = PLUGIN_CATEGORY_UTILITY;
  963. break;
  964. case kPlugCategMastering:
  965. category = PLUGIN_CATEGORY_DYNAMICS;
  966. break;
  967. case kPlugCategRoomFx:
  968. category = PLUGIN_CATEGORY_DELAY;
  969. break;
  970. case kPlugCategRestoration:
  971. category = PLUGIN_CATEGORY_UTILITY;
  972. break;
  973. case kPlugCategGenerator:
  974. category = PLUGIN_CATEGORY_SYNTH;
  975. break;
  976. default:
  977. if (effect->flags & effFlagsIsSynth)
  978. category = PLUGIN_CATEGORY_SYNTH;
  979. else
  980. category = PLUGIN_CATEGORY_NONE;
  981. break;
  982. }
  983. // get everything else
  984. uint hints = 0x0;
  985. uint audioIns = static_cast<uint>(std::max(0, effect->numInputs));
  986. uint audioOuts = static_cast<uint>(std::max(0, effect->numOutputs));
  987. uint midiIns = 0;
  988. uint midiOuts = 0;
  989. uint parameters = static_cast<uint>(std::max(0, effect->numParams));
  990. if (effect->flags & effFlagsHasEditor)
  991. hints |= PLUGIN_HAS_CUSTOM_UI;
  992. if (effect->flags & effFlagsIsSynth)
  993. {
  994. hints |= PLUGIN_IS_SYNTH;
  995. midiIns = 1;
  996. }
  997. if (vstPluginCanDo(effect, "receiveVstEvents") || vstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) != 0)
  998. midiIns = 1;
  999. if (vstPluginCanDo(effect, "sendVstEvents") || vstPluginCanDo(effect, "sendVstMidiEvent"))
  1000. midiOuts = 1;
  1001. // -----------------------------------------------------------------------
  1002. // start crash-free plugin test
  1003. if (doInit)
  1004. {
  1005. if (gVstNeedsIdle)
  1006. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1007. effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f);
  1008. effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f);
  1009. if (gVstNeedsIdle)
  1010. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1011. // Plugin might call wantMidi() during resume
  1012. if (midiIns == 0 && gVstWantsMidi)
  1013. {
  1014. midiIns = 1;
  1015. }
  1016. float* bufferAudioIn[std::max(1U, audioIns)];
  1017. float* bufferAudioOut[std::max(1U, audioOuts)];
  1018. if (audioIns == 0)
  1019. {
  1020. bufferAudioIn[0] = nullptr;
  1021. }
  1022. else
  1023. {
  1024. for (uint j=0; j < audioIns; ++j)
  1025. {
  1026. bufferAudioIn[j] = new float[kBufferSize];
  1027. carla_zeroFloats(bufferAudioIn[j], kBufferSize);
  1028. }
  1029. }
  1030. if (audioOuts == 0)
  1031. {
  1032. bufferAudioOut[0] = nullptr;
  1033. }
  1034. else
  1035. {
  1036. for (uint j=0; j < audioOuts; ++j)
  1037. {
  1038. bufferAudioOut[j] = new float[kBufferSize];
  1039. carla_zeroFloats(bufferAudioOut[j], kBufferSize);
  1040. }
  1041. }
  1042. struct VstEventsFixed {
  1043. int32_t numEvents;
  1044. intptr_t reserved;
  1045. VstEvent* data[2];
  1046. VstEventsFixed()
  1047. : numEvents(0),
  1048. reserved(0)
  1049. {
  1050. data[0] = data[1] = nullptr;
  1051. }
  1052. } events;
  1053. VstMidiEvent midiEvents[2];
  1054. carla_zeroStructs(midiEvents, 2);
  1055. midiEvents[0].type = kVstMidiType;
  1056. midiEvents[0].byteSize = sizeof(VstMidiEvent);
  1057. midiEvents[0].midiData[0] = char(MIDI_STATUS_NOTE_ON);
  1058. midiEvents[0].midiData[1] = 64;
  1059. midiEvents[0].midiData[2] = 100;
  1060. midiEvents[1].type = kVstMidiType;
  1061. midiEvents[1].byteSize = sizeof(VstMidiEvent);
  1062. midiEvents[1].midiData[0] = char(MIDI_STATUS_NOTE_OFF);
  1063. midiEvents[1].midiData[1] = 64;
  1064. midiEvents[1].deltaFrames = kBufferSize/2;
  1065. events.numEvents = 2;
  1066. events.data[0] = (VstEvent*)&midiEvents[0];
  1067. events.data[1] = (VstEvent*)&midiEvents[1];
  1068. // processing
  1069. gVstIsProcessing = true;
  1070. if (midiIns > 0)
  1071. effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f);
  1072. if ((effect->flags & effFlagsCanReplacing) > 0 && effect->processReplacing != nullptr && effect->processReplacing != effect->DECLARE_VST_DEPRECATED(process))
  1073. effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  1074. else if (effect->DECLARE_VST_DEPRECATED(process) != nullptr)
  1075. effect->DECLARE_VST_DEPRECATED(process)(effect, bufferAudioIn, bufferAudioOut, kBufferSize);
  1076. else
  1077. DISCOVERY_OUT("error", "Plugin doesn't have a process function");
  1078. gVstIsProcessing = false;
  1079. effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f);
  1080. effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
  1081. if (gVstNeedsIdle)
  1082. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1083. for (uint j=0; j < audioIns; ++j)
  1084. delete[] bufferAudioIn[j];
  1085. for (uint j=0; j < audioOuts; ++j)
  1086. delete[] bufferAudioOut[j];
  1087. }
  1088. // end crash-free plugin test
  1089. // -----------------------------------------------------------------------
  1090. DISCOVERY_OUT("init", "-----------");
  1091. DISCOVERY_OUT("build", BINARY_NATIVE);
  1092. DISCOVERY_OUT("hints", hints);
  1093. DISCOVERY_OUT("category", getPluginCategoryAsString(category));
  1094. DISCOVERY_OUT("name", cName.buffer());
  1095. DISCOVERY_OUT("label", cProduct.buffer());
  1096. DISCOVERY_OUT("maker", cVendor.buffer());
  1097. DISCOVERY_OUT("uniqueId", gVstCurrentUniqueId);
  1098. DISCOVERY_OUT("audio.ins", audioIns);
  1099. DISCOVERY_OUT("audio.outs", audioOuts);
  1100. DISCOVERY_OUT("midi.ins", midiIns);
  1101. DISCOVERY_OUT("midi.outs", midiOuts);
  1102. DISCOVERY_OUT("parameters.ins", parameters);
  1103. DISCOVERY_OUT("end", "------------");
  1104. gVstWantsMidi = false;
  1105. gVstWantsTime = false;
  1106. if (! isShell)
  1107. break;
  1108. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1109. effect = nullptr;
  1110. }
  1111. uniqueIds.clear();
  1112. if (effect != nullptr)
  1113. {
  1114. if (gVstNeedsIdle)
  1115. effect->dispatcher(effect, DECLARE_VST_DEPRECATED(effIdle), 0, 0, nullptr, 0.0f);
  1116. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  1117. }
  1118. #ifdef CARLA_OS_MAC
  1119. if (bundleRef != nullptr)
  1120. {
  1121. CFBundleCloseBundleResourceMap(bundleRef, resFileId);
  1122. CFBundleUnloadExecutable(bundleRef);
  1123. CFRelease(bundleRef);
  1124. }
  1125. #else
  1126. return;
  1127. // unused
  1128. (void)filename;
  1129. #endif
  1130. }
  1131. #endif // ! USING_JUCE_FOR_VST2
  1132. #ifdef USING_JUCE
  1133. // -------------------------------------------------------------------------------------------------------------------
  1134. // find all available plugin audio ports
  1135. static void findMaxTotalChannels(juce::AudioProcessor* const filter, int& maxTotalIns, int& maxTotalOuts)
  1136. {
  1137. filter->enableAllBuses();
  1138. int numInputBuses = filter->getBusCount(true);
  1139. int numOutputBuses = filter->getBusCount(false);
  1140. if (numInputBuses > 1 || numOutputBuses > 1)
  1141. {
  1142. maxTotalIns = maxTotalOuts = 0;
  1143. for (int i = 0; i < numInputBuses; ++i)
  1144. maxTotalIns += filter->getChannelCountOfBus(true, i);
  1145. for (int i = 0; i < numOutputBuses; ++i)
  1146. maxTotalOuts += filter->getChannelCountOfBus(false, i);
  1147. }
  1148. else
  1149. {
  1150. maxTotalIns = numInputBuses > 0 ? filter->getBus(true, 0)->getMaxSupportedChannels(64) : 0;
  1151. maxTotalOuts = numOutputBuses > 0 ? filter->getBus(false, 0)->getMaxSupportedChannels(64) : 0;
  1152. }
  1153. }
  1154. // -------------------------------------------------------------------------------------------------------------------
  1155. static bool do_juce_check(const char* const filename_, const char* const stype, const bool doInit)
  1156. {
  1157. CARLA_SAFE_ASSERT_RETURN(stype != nullptr && stype[0] != 0, false) // FIXME
  1158. carla_debug("do_juce_check(%s, %s, %s)", filename_, stype, bool2str(doInit));
  1159. carla_juce_init();
  1160. juce::String filename;
  1161. #ifdef CARLA_OS_WIN
  1162. // Fix for wine usage
  1163. if (juce::File("Z:\\usr\\").isDirectory() && filename_[0] == '/')
  1164. {
  1165. filename = filename_;
  1166. filename.replace("/", "\\");
  1167. filename = "Z:" + filename;
  1168. }
  1169. else
  1170. #endif
  1171. filename = juce::File(filename_).getFullPathName();
  1172. CarlaScopedPointer<juce::AudioPluginFormat> pluginFormat;
  1173. /* */ if (std::strcmp(stype, "VST2") == 0)
  1174. {
  1175. #if JUCE_PLUGINHOST_VST
  1176. pluginFormat = new juce::VSTPluginFormat();
  1177. #else
  1178. DISCOVERY_OUT("error", "VST2 support not available");
  1179. return false;
  1180. #endif
  1181. }
  1182. else if (std::strcmp(stype, "VST3") == 0)
  1183. {
  1184. #if JUCE_PLUGINHOST_VST3
  1185. pluginFormat = new juce::VST3PluginFormat();
  1186. #else
  1187. DISCOVERY_OUT("error", "VST3 support not available");
  1188. return false;
  1189. #endif
  1190. }
  1191. else if (std::strcmp(stype, "AU") == 0)
  1192. {
  1193. #if JUCE_PLUGINHOST_AU
  1194. pluginFormat = new juce::AudioUnitPluginFormat();
  1195. #else
  1196. DISCOVERY_OUT("error", "AU support not available");
  1197. return false;
  1198. #endif
  1199. }
  1200. if (pluginFormat == nullptr)
  1201. {
  1202. DISCOVERY_OUT("error", stype << " support not available");
  1203. return false;
  1204. }
  1205. #ifdef CARLA_OS_WIN
  1206. CARLA_CUSTOM_SAFE_ASSERT_RETURN("Plugin file/folder does not exist", juce::File(filename).exists(), false);
  1207. #endif
  1208. CARLA_SAFE_ASSERT_RETURN(pluginFormat->fileMightContainThisPluginType(filename), false);
  1209. juce::OwnedArray<juce::PluginDescription> results;
  1210. pluginFormat->findAllTypesForFile(results, filename);
  1211. if (results.size() == 0)
  1212. {
  1213. #if defined(CARLA_OS_MAC) && defined(__aarch64__)
  1214. if (std::strcmp(stype, "VST2") == 0 || std::strcmp(stype, "VST3") == 0)
  1215. return true;
  1216. #endif
  1217. DISCOVERY_OUT("error", "No plugins found");
  1218. return false;
  1219. }
  1220. for (juce::PluginDescription **it = results.begin(), **end = results.end(); it != end; ++it)
  1221. {
  1222. juce::PluginDescription* const desc(*it);
  1223. uint hints = 0x0;
  1224. int audioIns = desc->numInputChannels;
  1225. int audioOuts = desc->numOutputChannels;
  1226. int midiIns = 0;
  1227. int midiOuts = 0;
  1228. int parameters = 0;
  1229. if (desc->isInstrument)
  1230. {
  1231. hints |= PLUGIN_IS_SYNTH;
  1232. midiIns = 1;
  1233. }
  1234. if (doInit)
  1235. {
  1236. if (std::unique_ptr<juce::AudioPluginInstance> instance
  1237. = pluginFormat->createInstanceFromDescription(*desc, kSampleRate, kBufferSize))
  1238. {
  1239. carla_juce_idle();
  1240. findMaxTotalChannels(instance.get(), audioIns, audioOuts);
  1241. instance->refreshParameterList();
  1242. parameters = instance->getParameters().size();
  1243. if (instance->hasEditor())
  1244. hints |= PLUGIN_HAS_CUSTOM_UI;
  1245. if (instance->acceptsMidi())
  1246. midiIns = 1;
  1247. if (instance->producesMidi())
  1248. midiOuts = 1;
  1249. }
  1250. }
  1251. DISCOVERY_OUT("init", "-----------");
  1252. DISCOVERY_OUT("build", BINARY_NATIVE);
  1253. DISCOVERY_OUT("hints", hints);
  1254. DISCOVERY_OUT("category", getPluginCategoryAsString(getPluginCategoryFromName(desc->category.toRawUTF8())));
  1255. DISCOVERY_OUT("name", desc->descriptiveName);
  1256. DISCOVERY_OUT("label", desc->name);
  1257. DISCOVERY_OUT("maker", desc->manufacturerName);
  1258. DISCOVERY_OUT("uniqueId", desc->uid);
  1259. DISCOVERY_OUT("audio.ins", audioIns);
  1260. DISCOVERY_OUT("audio.outs", audioOuts);
  1261. DISCOVERY_OUT("midi.ins", midiIns);
  1262. DISCOVERY_OUT("midi.outs", midiOuts);
  1263. DISCOVERY_OUT("parameters.ins", parameters);
  1264. DISCOVERY_OUT("end", "------------");
  1265. }
  1266. carla_juce_idle();
  1267. carla_juce_cleanup();
  1268. return false;
  1269. }
  1270. #endif // USING_JUCE_FOR_VST2
  1271. static void do_fluidsynth_check(const char* const filename, const PluginType type, const bool doInit)
  1272. {
  1273. #ifdef HAVE_FLUIDSYNTH
  1274. const water::String jfilename = water::String(water::CharPointer_UTF8(filename));
  1275. const water::File file(jfilename);
  1276. if (! file.existsAsFile())
  1277. {
  1278. DISCOVERY_OUT("error", "Requested file is not valid or does not exist");
  1279. return;
  1280. }
  1281. if (type == PLUGIN_SF2 && ! fluid_is_soundfont(filename))
  1282. {
  1283. DISCOVERY_OUT("error", "Not a SF2 file");
  1284. return;
  1285. }
  1286. int programs = 0;
  1287. if (doInit)
  1288. {
  1289. fluid_settings_t* const f_settings = new_fluid_settings();
  1290. CARLA_SAFE_ASSERT_RETURN(f_settings != nullptr,);
  1291. fluid_synth_t* const f_synth = new_fluid_synth(f_settings);
  1292. CARLA_SAFE_ASSERT_RETURN(f_synth != nullptr,);
  1293. const int f_id_test = fluid_synth_sfload(f_synth, filename, 0);
  1294. if (f_id_test < 0)
  1295. {
  1296. DISCOVERY_OUT("error", "Failed to load SF2 file");
  1297. return;
  1298. }
  1299. #if FLUIDSYNTH_VERSION_MAJOR >= 2
  1300. const int f_id = f_id_test;
  1301. #else
  1302. const uint f_id = static_cast<uint>(f_id_test);
  1303. #endif
  1304. if (fluid_sfont_t* const f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id))
  1305. {
  1306. #if FLUIDSYNTH_VERSION_MAJOR >= 2
  1307. fluid_sfont_iteration_start(f_sfont);
  1308. for (; fluid_sfont_iteration_next(f_sfont);)
  1309. ++programs;
  1310. #else
  1311. fluid_preset_t f_preset;
  1312. f_sfont->iteration_start(f_sfont);
  1313. for (; f_sfont->iteration_next(f_sfont, &f_preset);)
  1314. ++programs;
  1315. #endif
  1316. }
  1317. delete_fluid_synth(f_synth);
  1318. delete_fluid_settings(f_settings);
  1319. }
  1320. CarlaString name(file.getFileNameWithoutExtension().toRawUTF8());
  1321. CarlaString label(name);
  1322. // 2 channels
  1323. DISCOVERY_OUT("init", "-----------");
  1324. DISCOVERY_OUT("build", BINARY_NATIVE);
  1325. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  1326. DISCOVERY_OUT("category", "synth");
  1327. DISCOVERY_OUT("name", name.buffer());
  1328. DISCOVERY_OUT("label", label.buffer());
  1329. DISCOVERY_OUT("audio.outs", 2);
  1330. DISCOVERY_OUT("midi.ins", 1);
  1331. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  1332. DISCOVERY_OUT("parameters.outs", 1);
  1333. DISCOVERY_OUT("end", "------------");
  1334. // 16 channels
  1335. if (doInit && (name.isEmpty() || programs <= 1))
  1336. return;
  1337. name += " (16 outputs)";
  1338. DISCOVERY_OUT("init", "-----------");
  1339. DISCOVERY_OUT("build", BINARY_NATIVE);
  1340. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  1341. DISCOVERY_OUT("category", "synth");
  1342. DISCOVERY_OUT("name", name.buffer());
  1343. DISCOVERY_OUT("label", label.buffer());
  1344. DISCOVERY_OUT("audio.outs", 32);
  1345. DISCOVERY_OUT("midi.ins", 1);
  1346. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  1347. DISCOVERY_OUT("parameters.outs", 1);
  1348. DISCOVERY_OUT("end", "------------");
  1349. #else // HAVE_FLUIDSYNTH
  1350. DISCOVERY_OUT("error", "SF2 support not available");
  1351. return;
  1352. // unused
  1353. (void)filename;
  1354. (void)type;
  1355. (void)doInit;
  1356. #endif
  1357. }
  1358. // -------------------------------------------------------------------------------------------------------------------
  1359. #ifndef BUILD_BRIDGE
  1360. static void do_jsfx_check(const char* const filename, bool doInit)
  1361. {
  1362. JsusFx::init();
  1363. // TODO(jsfx) determinine the import search path correctly
  1364. water::File file(filename);
  1365. CarlaJsusFxPathLibrary pathLibrary(file);
  1366. CarlaJsusFx effect(pathLibrary);
  1367. effect.setQuiet(true);
  1368. uint hints = 0;
  1369. ///
  1370. JsusFxFileAPI_Basic fileAPI;
  1371. effect.fileAPI = &fileAPI;
  1372. fileAPI.init(effect.m_vm);
  1373. JsusFxGfx gfxAPI;
  1374. effect.gfx = &gfxAPI;
  1375. gfxAPI.init(effect.m_vm);
  1376. ///
  1377. if (doInit)
  1378. {
  1379. int compileFlags =
  1380. JsusFx::kCompileFlag_CompileSerializeSection |
  1381. JsusFx::kCompileFlag_CompileGraphicsSection;
  1382. if (!effect.compile(pathLibrary, filename, compileFlags))
  1383. {
  1384. DISCOVERY_OUT("error", "Cannot compile the JSFX plugin");
  1385. return;
  1386. }
  1387. #if 0 // TODO(jsfx) when supporting custom graphics
  1388. if (effect.hasGraphicsSection())
  1389. hints |= PLUGIN_HAS_CUSTOM_UI;
  1390. // TODO(jsfx) there should be a way to check this without compiling
  1391. #endif
  1392. }
  1393. else
  1394. {
  1395. if (!effect.readHeader(pathLibrary, filename))
  1396. {
  1397. DISCOVERY_OUT("error", "Cannot read the JSFX header");
  1398. return;
  1399. }
  1400. }
  1401. // jsusfx lacks validity checks currently,
  1402. // ensure we have at least the description (required)
  1403. if (effect.desc[0] == '\0')
  1404. {
  1405. DISCOVERY_OUT("error", "The JSFX header is invalid");
  1406. return;
  1407. }
  1408. water::String baseName = water::File(filename).getFileNameWithoutExtension();
  1409. // NOTE: count can be -1 in case of "none"
  1410. uint32_t audioIns = (effect.numInputs == -1) ? 0 : (uint32_t)effect.numInputs;
  1411. uint32_t audioOuts = (effect.numOutputs == -1) ? 0 : (uint32_t)effect.numOutputs;
  1412. uint32_t midiIns = 1;
  1413. uint32_t midiOuts = 1;
  1414. uint32_t parameters = 0;
  1415. for (uint32_t sliderIndex = 0; sliderIndex < JsusFx::kMaxSliders; ++sliderIndex)
  1416. {
  1417. if (effect.sliders[sliderIndex].exists)
  1418. ++parameters;
  1419. }
  1420. DISCOVERY_OUT("init", "-----------");
  1421. DISCOVERY_OUT("build", BINARY_NATIVE);
  1422. DISCOVERY_OUT("hints", hints);
  1423. DISCOVERY_OUT("name", baseName.toRawUTF8());
  1424. DISCOVERY_OUT("label", filename);
  1425. DISCOVERY_OUT("audio.ins", audioIns);
  1426. DISCOVERY_OUT("audio.outs", audioOuts);
  1427. DISCOVERY_OUT("midi.ins", midiIns);
  1428. DISCOVERY_OUT("midi.outs", midiOuts);
  1429. DISCOVERY_OUT("parameters.ins", parameters);
  1430. DISCOVERY_OUT("end", "------------");
  1431. }
  1432. #endif
  1433. // ------------------------------ main entry point ------------------------------
  1434. int main(int argc, char* argv[])
  1435. {
  1436. if (argc != 3)
  1437. {
  1438. carla_stdout("usage: %s <type> </path/to/plugin>", argv[0]);
  1439. return 1;
  1440. }
  1441. const char* const stype = argv[1];
  1442. const char* const filename = argv[2];
  1443. const PluginType type = getPluginTypeFromString(stype);
  1444. CarlaString filenameCheck(filename);
  1445. filenameCheck.toLower();
  1446. bool openLib = false;
  1447. lib_t handle = nullptr;
  1448. switch (type)
  1449. {
  1450. case PLUGIN_LADSPA:
  1451. case PLUGIN_DSSI:
  1452. case PLUGIN_VST2:
  1453. openLib = true;
  1454. break;
  1455. case PLUGIN_VST3:
  1456. openLib = water::File(filename).existsAsFile();
  1457. break;
  1458. default:
  1459. break;
  1460. }
  1461. if (type != PLUGIN_SF2 && filenameCheck.contains("fluidsynth", true))
  1462. {
  1463. DISCOVERY_OUT("info", "skipping fluidsynth based plugin");
  1464. return 0;
  1465. }
  1466. #ifdef CARLA_OS_MAC
  1467. if (type == PLUGIN_VST2 && (filenameCheck.endsWith(".vst") || filenameCheck.endsWith(".vst/")))
  1468. openLib = false;
  1469. #endif
  1470. // ---------------------------------------------------------------------------------------------------------------
  1471. // Initialize OS features
  1472. // we want stuff in English so we can parse error messages
  1473. ::setlocale(LC_ALL, "C");
  1474. #ifndef CARLA_OS_WIN
  1475. carla_setenv("LC_ALL", "C");
  1476. #endif
  1477. #ifdef CARLA_OS_WIN
  1478. OleInitialize(nullptr);
  1479. CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
  1480. # ifndef __WINPTHREADS_VERSION
  1481. // (non-portable) initialization of statically linked pthread library
  1482. pthread_win32_process_attach_np();
  1483. pthread_win32_thread_attach_np();
  1484. # endif
  1485. #endif
  1486. // ---------------------------------------------------------------------------------------------------------------
  1487. if (openLib)
  1488. {
  1489. handle = lib_open(filename);
  1490. if (handle == nullptr)
  1491. {
  1492. print_lib_error(filename);
  1493. return 1;
  1494. }
  1495. }
  1496. // never do init for dssi-vst, takes too long and it's crashy
  1497. bool doInit = ! filenameCheck.contains("dssi-vst", true);
  1498. if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS") != nullptr)
  1499. doInit = false;
  1500. // ---------------------------------------------------------------------------------------------------------------
  1501. if (doInit && openLib && handle != nullptr)
  1502. {
  1503. // test fast loading & unloading DLL without initializing the plugin(s)
  1504. if (! lib_close(handle))
  1505. {
  1506. print_lib_error(filename);
  1507. return 1;
  1508. }
  1509. handle = lib_open(filename);
  1510. if (handle == nullptr)
  1511. {
  1512. print_lib_error(filename);
  1513. return 1;
  1514. }
  1515. }
  1516. #ifndef BUILD_BRIDGE
  1517. if (std::strcmp(filename, ":all") == 0)
  1518. {
  1519. do_cached_check(type);
  1520. return 0;
  1521. }
  1522. #endif
  1523. #ifdef CARLA_OS_MAC
  1524. // Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
  1525. switch (type)
  1526. {
  1527. case PLUGIN_LADSPA:
  1528. case PLUGIN_DSSI:
  1529. case PLUGIN_VST2:
  1530. case PLUGIN_VST3:
  1531. removeFileFromQuarantine(filename);
  1532. break;
  1533. default:
  1534. break;
  1535. }
  1536. #endif
  1537. #ifdef USING_JUCE
  1538. // some macOS plugins have not been yet ported to arm64, re-run them in x86_64 mode if discovery fails
  1539. bool retryJucePlugin = false;
  1540. #endif
  1541. switch (type)
  1542. {
  1543. case PLUGIN_LADSPA:
  1544. do_ladspa_check(handle, filename, doInit);
  1545. break;
  1546. case PLUGIN_DSSI:
  1547. do_dssi_check(handle, filename, doInit);
  1548. break;
  1549. #ifndef BUILD_BRIDGE
  1550. case PLUGIN_LV2:
  1551. do_lv2_check(filename, doInit);
  1552. break;
  1553. #endif
  1554. case PLUGIN_VST2:
  1555. #if defined(USING_JUCE) && JUCE_PLUGINHOST_VST
  1556. retryJucePlugin = do_juce_check(filename, "VST2", doInit);
  1557. #else
  1558. do_vst_check(handle, filename, doInit);
  1559. #endif
  1560. break;
  1561. case PLUGIN_VST3:
  1562. #if defined(USING_JUCE) && JUCE_PLUGINHOST_VST3
  1563. retryJucePlugin = do_juce_check(filename, "VST3", doInit);
  1564. #else
  1565. DISCOVERY_OUT("error", "VST3 support not available");
  1566. #endif
  1567. break;
  1568. case PLUGIN_AU:
  1569. #if defined(USING_JUCE) && JUCE_PLUGINHOST_AU
  1570. do_juce_check(filename, "AU", doInit);
  1571. #else
  1572. DISCOVERY_OUT("error", "AU support not available");
  1573. #endif
  1574. break;
  1575. #ifndef BUILD_BRIDGE
  1576. case PLUGIN_JSFX:
  1577. do_jsfx_check(filename, doInit);
  1578. break;
  1579. #endif
  1580. case PLUGIN_DLS:
  1581. case PLUGIN_GIG:
  1582. case PLUGIN_SF2:
  1583. do_fluidsynth_check(filename, type, doInit);
  1584. break;
  1585. default:
  1586. break;
  1587. }
  1588. #if defined(CARLA_OS_MAC) && defined(USING_JUCE) && defined(__aarch64__)
  1589. if (retryJucePlugin)
  1590. {
  1591. DISCOVERY_OUT("warning", "No plugins found while scanning in arm64 mode, will try x86_64 now");
  1592. cpu_type_t pref = CPU_TYPE_X86_64;
  1593. pid_t pid = -1;
  1594. posix_spawnattr_t attr;
  1595. posix_spawnattr_init(&attr);
  1596. CARLA_SAFE_ASSERT_RETURN(posix_spawnattr_setbinpref_np(&attr, 1, &pref, nullptr) == 0, 1);
  1597. CARLA_SAFE_ASSERT_RETURN(posix_spawn(&pid, argv[0], nullptr, &attr, argv, nullptr) == 0, 1);
  1598. posix_spawnattr_destroy(&attr);
  1599. if (pid > 0)
  1600. {
  1601. int status;
  1602. waitpid(pid, &status, 0);
  1603. }
  1604. }
  1605. #endif
  1606. if (openLib && handle != nullptr)
  1607. lib_close(handle);
  1608. // ---------------------------------------------------------------------------------------------------------------
  1609. #ifdef CARLA_OS_WIN
  1610. #ifndef __WINPTHREADS_VERSION
  1611. pthread_win32_thread_detach_np();
  1612. pthread_win32_process_detach_np();
  1613. #endif
  1614. CoUninitialize();
  1615. OleUninitialize();
  1616. #endif
  1617. return 0;
  1618. #ifdef USING_JUCE
  1619. // might be unused
  1620. (void)retryJucePlugin;
  1621. #endif
  1622. }
  1623. // -------------------------------------------------------------------------------------------------------------------