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

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