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

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