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

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