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

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