Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

carla-discovery.cpp 61KB

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