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 61KB

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