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.

carla-discovery.cpp 93KB

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