Collection of tools useful for audio production
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.

1164 lines
37KB

  1. /*
  2. * Carla Plugin discovery code
  3. * Copyright (C) 2011-2012 Filipe Coelho <falktx@gmail.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_includes.h"
  18. #include "carla_lib_includes.h"
  19. #include <cstdint>
  20. #include <cstdlib>
  21. #include <cstring>
  22. #include <iostream>
  23. #include <QtCore/QDir>
  24. #include <QtCore/QFileInfo>
  25. #include <QtCore/QUrl>
  26. #include "carla_ladspa.h"
  27. #include "carla_dssi.h"
  28. #include "carla_lv2.h"
  29. #include "carla_vst.h"
  30. #ifdef BUILD_NATIVE
  31. # ifdef WANT_FLUIDSYNTH
  32. # include "carla_fluidsynth.h"
  33. # endif
  34. # ifdef WANT_LINUXSAMPLER
  35. # include "carla_linuxsampler.h"
  36. # endif
  37. #endif
  38. #include "carla_backend.h"
  39. #define DISCOVERY_OUT(x, y) std::cout << "\ncarla-discovery::" << x << "::" << y << std::endl;
  40. // fake values to test plugins with
  41. const uint32_t bufferSize = 512;
  42. const double sampleRate = 44100.0;
  43. // Since discovery can find multi-architecture binaries, don't print ELF/EXE related errors
  44. void print_lib_error(const char* const filename)
  45. {
  46. const char* const error = lib_error(filename);
  47. if (error && strstr(error, "wrong ELF class") == nullptr && strstr(error, "Bad EXE format") == nullptr)
  48. DISCOVERY_OUT("error", error);
  49. }
  50. using namespace CarlaBackend;
  51. // ------------------------------ VST Stuff ------------------------------
  52. intptr_t VstCurrentUniqueId = 0;
  53. intptr_t VstHostCallback(AEffect* const effect, const int32_t opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt)
  54. {
  55. #if DEBUG
  56. qDebug("VstHostCallback(%p, opcode: %s, index: %i, value: " P_INTPTR ", opt: %f", effect, VstMasterOpcode2str(opcode), index, value, opt);
  57. #endif
  58. switch (opcode)
  59. {
  60. case audioMasterAutomate:
  61. if (effect)
  62. effect->setParameter(effect, index, opt);
  63. break;
  64. case audioMasterVersion:
  65. return kVstVersion;
  66. case audioMasterCurrentId:
  67. return VstCurrentUniqueId;
  68. case audioMasterGetTime:
  69. static VstTimeInfo_R timeInfo;
  70. memset(&timeInfo, 0, sizeof(VstTimeInfo_R));
  71. timeInfo.sampleRate = sampleRate;
  72. // Tempo
  73. timeInfo.tempo = 120.0;
  74. timeInfo.flags |= kVstTempoValid;
  75. // Time Signature
  76. timeInfo.timeSigNumerator = 4;
  77. timeInfo.timeSigDenominator = 4;
  78. timeInfo.flags |= kVstTimeSigValid;
  79. return (intptr_t)&timeInfo;
  80. case audioMasterTempoAt:
  81. // Deprecated in VST SDK 2.4
  82. return 120 * 10000;
  83. case audioMasterGetSampleRate:
  84. return sampleRate;
  85. case audioMasterGetBlockSize:
  86. return bufferSize;
  87. case audioMasterGetVendorString:
  88. strcpy((char*)ptr, "Cadence");
  89. break;
  90. case audioMasterGetProductString:
  91. strcpy((char*)ptr, "Carla-Discovery");
  92. break;
  93. case audioMasterGetVendorVersion:
  94. return 0x05; // 0.5
  95. case audioMasterCanDo:
  96. #if DEBUG
  97. qDebug("VstHostCallback:audioMasterCanDo - %s", (char*)ptr);
  98. #endif
  99. if (strcmp((char*)ptr, "supplyIdle") == 0)
  100. return 1;
  101. if (strcmp((char*)ptr, "sendVstEvents") == 0)
  102. return 1;
  103. if (strcmp((char*)ptr, "sendVstMidiEvent") == 0)
  104. return 1;
  105. if (strcmp((char*)ptr, "sendVstMidiEventFlagIsRealtime") == 0)
  106. return -1;
  107. if (strcmp((char*)ptr, "sendVstTimeInfo") == 0)
  108. return 1;
  109. if (strcmp((char*)ptr, "receiveVstEvents") == 0)
  110. return 1;
  111. if (strcmp((char*)ptr, "receiveVstMidiEvent") == 0)
  112. return 1;
  113. if (strcmp((char*)ptr, "receiveVstTimeInfo") == 0)
  114. return -1;
  115. if (strcmp((char*)ptr, "reportConnectionChanges") == 0)
  116. return -1;
  117. if (strcmp((char*)ptr, "acceptIOChanges") == 0)
  118. return -1;
  119. if (strcmp((char*)ptr, "sizeWindow") == 0)
  120. return 1;
  121. if (strcmp((char*)ptr, "offline") == 0)
  122. return -1;
  123. if (strcmp((char*)ptr, "openFileSelector") == 0)
  124. return -1;
  125. if (strcmp((char*)ptr, "closeFileSelector") == 0)
  126. return -1;
  127. if (strcmp((char*)ptr, "startStopProcess") == 0)
  128. return 1;
  129. if (strcmp((char*)ptr, "supportShell") == 0)
  130. return 1;
  131. if (strcmp((char*)ptr, "shellCategory") == 0)
  132. return 1;
  133. // unimplemented
  134. qWarning("VstHostCallback:audioMasterCanDo - Got unknown feature request '%s'", (char*)ptr);
  135. return 0;
  136. case audioMasterGetLanguage:
  137. return kVstLangEnglish;
  138. default:
  139. qDebug("VstHostCallback(%p, opcode: %s, index: %i, value: " P_INTPTR ", opt: %f", effect, VstMasterOpcode2str(opcode), index, value, opt);
  140. break;
  141. }
  142. return 0;
  143. Q_UNUSED(value);
  144. }
  145. // ------------------------------ Plugin Checks -----------------------------
  146. void do_ladspa_check(void* const lib_handle, const bool init)
  147. {
  148. const LADSPA_Descriptor_Function descfn = (LADSPA_Descriptor_Function)lib_symbol(lib_handle, "ladspa_descriptor");
  149. if (! descfn)
  150. {
  151. DISCOVERY_OUT("error", "Not a LADSPA plugin");
  152. return;
  153. }
  154. unsigned long i = 0;
  155. const LADSPA_Descriptor* descriptor;
  156. while ((descriptor = descfn(i++)))
  157. {
  158. int hints = 0;
  159. int audioIns = 0;
  160. int audioOuts = 0;
  161. int audioTotal = 0;
  162. int parametersIns = 0;
  163. int parametersOuts = 0;
  164. int parametersTotal = 0;
  165. for (unsigned long j=0; j < descriptor->PortCount; j++)
  166. {
  167. const LADSPA_PortDescriptor PortDescriptor = descriptor->PortDescriptors[j];
  168. if (LADSPA_IS_PORT_AUDIO(PortDescriptor))
  169. {
  170. if (LADSPA_IS_PORT_INPUT(PortDescriptor))
  171. audioIns += 1;
  172. else if (LADSPA_IS_PORT_OUTPUT(PortDescriptor))
  173. audioOuts += 1;
  174. audioTotal += 1;
  175. }
  176. else if (LADSPA_IS_PORT_CONTROL(PortDescriptor))
  177. {
  178. if (LADSPA_IS_PORT_INPUT(PortDescriptor))
  179. parametersIns += 1;
  180. else if (LADSPA_IS_PORT_OUTPUT(PortDescriptor) && strcmp(descriptor->PortNames[j], "latency") && strcmp(descriptor->PortNames[j], "_latency") && strcmp(descriptor->PortNames[j], "_sample-rate"))
  181. parametersOuts += 1;
  182. parametersTotal += 1;
  183. }
  184. }
  185. if (init)
  186. {
  187. // -----------------------------------------------------------------------
  188. // start crash-free plugin test
  189. const LADSPA_Handle handle = descriptor->instantiate(descriptor, sampleRate);
  190. if (! handle)
  191. {
  192. DISCOVERY_OUT("error", "Failed to init LADSPA plugin");
  193. continue;
  194. }
  195. LADSPA_Data bufferAudio[bufferSize][audioTotal];
  196. memset(bufferAudio, 0, sizeof(float)*bufferSize*audioTotal);
  197. LADSPA_Data bufferParams[parametersTotal];
  198. memset(bufferParams, 0, sizeof(float)*parametersTotal);
  199. LADSPA_Data min, max, def;
  200. for (unsigned long j=0, iA=0, iP=0; j < descriptor->PortCount; j++)
  201. {
  202. const LADSPA_PortDescriptor PortType = descriptor->PortDescriptors[j];
  203. const LADSPA_PortRangeHint PortHint = descriptor->PortRangeHints[j];
  204. if (LADSPA_IS_PORT_AUDIO(PortType))
  205. {
  206. descriptor->connect_port(handle, j, bufferAudio[iA++]);
  207. }
  208. else if (LADSPA_IS_PORT_CONTROL(PortType))
  209. {
  210. // min value
  211. if (LADSPA_IS_HINT_BOUNDED_BELOW(PortHint.HintDescriptor))
  212. min = PortHint.LowerBound;
  213. else
  214. min = 0.0f;
  215. // max value
  216. if (LADSPA_IS_HINT_BOUNDED_ABOVE(PortHint.HintDescriptor))
  217. max = PortHint.UpperBound;
  218. else
  219. max = 1.0f;
  220. if (min > max)
  221. max = min;
  222. else if (max < min)
  223. min = max;
  224. if (max - min == 0.0f)
  225. {
  226. DISCOVERY_OUT("error", "Broken parameter: max - min == 0");
  227. max = min + 0.1f;
  228. }
  229. // default value
  230. def = get_default_ladspa_port_value(PortHint.HintDescriptor, min, max);
  231. if (def < min)
  232. def = min;
  233. else if (def > max)
  234. def = max;
  235. if (LADSPA_IS_HINT_SAMPLE_RATE(PortHint.HintDescriptor))
  236. {
  237. min *= sampleRate;
  238. max *= sampleRate;
  239. def *= sampleRate;
  240. }
  241. if (LADSPA_IS_PORT_OUTPUT(PortType) && (strcmp(descriptor->PortNames[j], "latency") == 0 || strcmp(descriptor->PortNames[j], "_latency") == 0))
  242. {
  243. // latency parameter
  244. min = 0.0f;
  245. max = sampleRate;
  246. def = 0.0f;
  247. }
  248. bufferParams[iP] = def;
  249. descriptor->connect_port(handle, j, &bufferParams[iP++]);
  250. }
  251. }
  252. if (descriptor->activate)
  253. descriptor->activate(handle);
  254. descriptor->run(handle, bufferSize);
  255. if (descriptor->deactivate)
  256. descriptor->deactivate(handle);
  257. if (descriptor->cleanup)
  258. descriptor->cleanup(handle);
  259. // end crash-free plugin test
  260. // -----------------------------------------------------------------------
  261. }
  262. DISCOVERY_OUT("init", "-----------");
  263. DISCOVERY_OUT("name", descriptor->Name);
  264. DISCOVERY_OUT("label", descriptor->Label);
  265. DISCOVERY_OUT("maker", descriptor->Maker);
  266. DISCOVERY_OUT("copyright", descriptor->Copyright);
  267. DISCOVERY_OUT("unique_id", descriptor->UniqueID);
  268. DISCOVERY_OUT("hints", hints);
  269. DISCOVERY_OUT("audio.ins", audioIns);
  270. DISCOVERY_OUT("audio.outs", audioOuts);
  271. DISCOVERY_OUT("audio.total", audioTotal);
  272. DISCOVERY_OUT("parameters.ins", parametersIns);
  273. DISCOVERY_OUT("parameters.outs", parametersOuts);
  274. DISCOVERY_OUT("parameters.total", parametersTotal);
  275. DISCOVERY_OUT("build", BINARY_NATIVE);
  276. DISCOVERY_OUT("end", "------------");
  277. }
  278. }
  279. void do_dssi_check(void* const lib_handle, const bool init)
  280. {
  281. const DSSI_Descriptor_Function descfn = (DSSI_Descriptor_Function)lib_symbol(lib_handle, "dssi_descriptor");
  282. if (! descfn)
  283. {
  284. DISCOVERY_OUT("error", "Not a DSSI plugin");
  285. return;
  286. }
  287. unsigned long i = 0;
  288. const DSSI_Descriptor* descriptor;
  289. while ((descriptor = descfn(i++)))
  290. {
  291. const LADSPA_Descriptor* const ldescriptor = descriptor->LADSPA_Plugin;
  292. int hints = 0;
  293. int audioIns = 0;
  294. int audioOuts = 0;
  295. int audioTotal = 0;
  296. int midiIns = 0;
  297. int midiTotal = 0;
  298. int parametersIns = 0;
  299. int parametersOuts = 0;
  300. int parametersTotal = 0;
  301. int programsTotal = 0;
  302. for (unsigned long j=0; j < ldescriptor->PortCount; j++)
  303. {
  304. const LADSPA_PortDescriptor PortDescriptor = ldescriptor->PortDescriptors[j];
  305. if (LADSPA_IS_PORT_AUDIO(PortDescriptor))
  306. {
  307. if (LADSPA_IS_PORT_INPUT(PortDescriptor))
  308. audioIns += 1;
  309. else if (LADSPA_IS_PORT_OUTPUT(PortDescriptor))
  310. audioOuts += 1;
  311. audioTotal += 1;
  312. }
  313. else if (LADSPA_IS_PORT_CONTROL(PortDescriptor))
  314. {
  315. if (LADSPA_IS_PORT_INPUT(PortDescriptor))
  316. parametersIns += 1;
  317. else if (LADSPA_IS_PORT_OUTPUT(PortDescriptor) && strcmp(ldescriptor->PortNames[j], "latency") && strcmp(ldescriptor->PortNames[j], "_latency") && strcmp(ldescriptor->PortNames[j], "_sample-rate"))
  318. parametersOuts += 1;
  319. parametersTotal += 1;
  320. }
  321. }
  322. if (descriptor->run_synth || descriptor->run_multiple_synths)
  323. midiIns = midiTotal = 1;
  324. if (midiIns > 0 && audioOuts > 0)
  325. hints |= PLUGIN_IS_SYNTH;
  326. if (init)
  327. {
  328. // -----------------------------------------------------------------------
  329. // start crash-free plugin test
  330. const LADSPA_Handle handle = ldescriptor->instantiate(ldescriptor, sampleRate);
  331. if (! handle)
  332. {
  333. DISCOVERY_OUT("error", "Failed to init DSSI plugin");
  334. continue;
  335. }
  336. // we can only get program info per-handle
  337. if (descriptor->get_program)
  338. {
  339. while ((descriptor->get_program(handle, programsTotal++)))
  340. continue;
  341. }
  342. LADSPA_Data bufferAudio[bufferSize][audioTotal];
  343. memset(bufferAudio, 0, sizeof(float)*bufferSize*audioTotal);
  344. LADSPA_Data bufferParams[parametersTotal];
  345. memset(bufferParams, 0, sizeof(float)*parametersTotal);
  346. LADSPA_Data min, max, def;
  347. for (unsigned long j=0, iA=0, iP=0; j < ldescriptor->PortCount; j++)
  348. {
  349. const LADSPA_PortDescriptor PortType = ldescriptor->PortDescriptors[j];
  350. const LADSPA_PortRangeHint PortHint = ldescriptor->PortRangeHints[j];
  351. if (LADSPA_IS_PORT_AUDIO(PortType))
  352. {
  353. ldescriptor->connect_port(handle, j, bufferAudio[iA++]);
  354. }
  355. else if (LADSPA_IS_PORT_CONTROL(PortType))
  356. {
  357. // min value
  358. if (LADSPA_IS_HINT_BOUNDED_BELOW(PortHint.HintDescriptor))
  359. min = PortHint.LowerBound;
  360. else
  361. min = 0.0f;
  362. // max value
  363. if (LADSPA_IS_HINT_BOUNDED_ABOVE(PortHint.HintDescriptor))
  364. max = PortHint.UpperBound;
  365. else
  366. max = 1.0f;
  367. if (min > max)
  368. max = min;
  369. else if (max < min)
  370. min = max;
  371. if (max - min == 0.0f)
  372. {
  373. DISCOVERY_OUT("error", "Broken parameter: max - min == 0");
  374. max = min + 0.1f;
  375. }
  376. // default value
  377. def = get_default_ladspa_port_value(PortHint.HintDescriptor, min, max);
  378. if (def < min)
  379. def = min;
  380. else if (def > max)
  381. def = max;
  382. if (LADSPA_IS_HINT_SAMPLE_RATE(PortHint.HintDescriptor))
  383. {
  384. min *= sampleRate;
  385. max *= sampleRate;
  386. def *= sampleRate;
  387. }
  388. if (LADSPA_IS_PORT_OUTPUT(PortType) && (strcmp(ldescriptor->PortNames[j], "latency") == 0 || strcmp(ldescriptor->PortNames[j], "_latency") == 0))
  389. {
  390. // latency parameter
  391. min = 0.0f;
  392. max = sampleRate;
  393. def = 0.0f;
  394. }
  395. bufferParams[iP] = def;
  396. ldescriptor->connect_port(handle, j, &bufferParams[iP++]);
  397. }
  398. }
  399. if (ldescriptor->activate)
  400. ldescriptor->activate(handle);
  401. if (descriptor->run_synth || descriptor->run_multiple_synths)
  402. {
  403. snd_seq_event_t midiEvents[2];
  404. memset(midiEvents, 0, sizeof(snd_seq_event_t)*2);
  405. const unsigned long midiEventCount = 2;
  406. midiEvents[0].type = SND_SEQ_EVENT_NOTEON;
  407. midiEvents[0].data.note.note = 64;
  408. midiEvents[0].data.note.velocity = 100;
  409. midiEvents[1].type = SND_SEQ_EVENT_NOTEOFF;
  410. midiEvents[1].data.note.note = 64;
  411. midiEvents[1].data.note.velocity = 0;
  412. midiEvents[1].time.tick = bufferSize/2;
  413. if (descriptor->run_multiple_synths && ! descriptor->run_synth)
  414. {
  415. LADSPA_Handle handlePtr[1] = { handle };
  416. snd_seq_event_t* midiEventsPtr[1] = { midiEvents };
  417. unsigned long midiEventCountPtr[1] = { midiEventCount };
  418. descriptor->run_multiple_synths(1, handlePtr, bufferSize, midiEventsPtr, midiEventCountPtr);
  419. }
  420. else
  421. descriptor->run_synth(handle, bufferSize, midiEvents, midiEventCount);
  422. }
  423. else
  424. ldescriptor->run(handle, bufferSize);
  425. if (ldescriptor->deactivate)
  426. ldescriptor->deactivate(handle);
  427. if (ldescriptor->cleanup)
  428. ldescriptor->cleanup(handle);
  429. // end crash-free plugin test
  430. // -----------------------------------------------------------------------
  431. }
  432. DISCOVERY_OUT("init", "-----------");
  433. DISCOVERY_OUT("name", ldescriptor->Name);
  434. DISCOVERY_OUT("label", ldescriptor->Label);
  435. DISCOVERY_OUT("maker", ldescriptor->Maker);
  436. DISCOVERY_OUT("copyright", ldescriptor->Copyright);
  437. DISCOVERY_OUT("unique_id", ldescriptor->UniqueID);
  438. DISCOVERY_OUT("hints", hints);
  439. DISCOVERY_OUT("audio.ins", audioIns);
  440. DISCOVERY_OUT("audio.outs", audioOuts);
  441. DISCOVERY_OUT("audio.total", audioTotal);
  442. DISCOVERY_OUT("midi.ins", midiIns);
  443. DISCOVERY_OUT("midi.total", midiTotal);
  444. DISCOVERY_OUT("parameters.ins", parametersIns);
  445. DISCOVERY_OUT("parameters.outs", parametersOuts);
  446. DISCOVERY_OUT("parameters.total", parametersTotal);
  447. DISCOVERY_OUT("programs.total", programsTotal);
  448. DISCOVERY_OUT("build", BINARY_NATIVE);
  449. DISCOVERY_OUT("end", "------------");
  450. }
  451. }
  452. void do_lv2_check(const char* const bundle, const bool init)
  453. {
  454. // Convert bundle filename to URI
  455. QString qBundle(QUrl::fromLocalFile(bundle).toString());
  456. if (! qBundle.endsWith(QDir::separator()))
  457. qBundle += QDir::separator();
  458. // Load bundle
  459. Lilv::Node lilvBundle(Lv2World.new_uri(qBundle.toUtf8().constData()));
  460. Lv2World.load_bundle(lilvBundle);
  461. // Load plugins in this bundle
  462. const Lilv::Plugins lilvPlugins = Lv2World.get_all_plugins();
  463. // Get all plugin URIs in this bundle
  464. QStringList URIs;
  465. LILV_FOREACH(plugins, i, lilvPlugins)
  466. {
  467. Lilv::Plugin lilvPlugin(lilv_plugins_get(lilvPlugins, i));
  468. URIs.append(QString(lilvPlugin.get_uri().as_string()));
  469. }
  470. // Get & check every plugin-instance
  471. for (int i=0; i < URIs.count(); i++)
  472. {
  473. const LV2_RDF_Descriptor* const rdf_descriptor = lv2_rdf_new(URIs.at(i).toUtf8().constData());
  474. if (init)
  475. {
  476. // test if DLL is loadable
  477. void* const lib_handle = lib_open(rdf_descriptor->Binary);
  478. if (! lib_handle)
  479. {
  480. print_lib_error(rdf_descriptor->Binary);
  481. continue;
  482. }
  483. lib_close(lib_handle);
  484. // test if we support all required ports and features
  485. bool supported = true;
  486. for (uint32_t j=0; j < rdf_descriptor->PortCount; j++)
  487. {
  488. const LV2_RDF_Port* const Port = &rdf_descriptor->Ports[j];
  489. bool validPort = (LV2_IS_PORT_CONTROL(Port->Type) || LV2_IS_PORT_AUDIO(Port->Type) || LV2_IS_PORT_ATOM_SEQUENCE(Port->Type) /*|| LV2_IS_PORT_CV(Port->Type)*/ || LV2_IS_PORT_EVENT(Port->Type) || LV2_IS_PORT_MIDI_LL(Port->Type));
  490. if (! (validPort || LV2_IS_PORT_OPTIONAL(Port->Properties)))
  491. {
  492. DISCOVERY_OUT("error", "plugin requires a non-supported port type, port-name: " << Port->Name);
  493. supported = false;
  494. break;
  495. }
  496. }
  497. for (uint32_t j=0; j < rdf_descriptor->FeatureCount && supported; j++)
  498. {
  499. const LV2_RDF_Feature* const Feature = &rdf_descriptor->Features[j];
  500. if (LV2_IS_FEATURE_REQUIRED(Feature->Type) && ! is_lv2_feature_supported(Feature->URI))
  501. {
  502. DISCOVERY_OUT("error", "plugin requires a non-supported feature " << Feature->URI);
  503. supported = false;
  504. break;
  505. }
  506. }
  507. if (! supported)
  508. continue;
  509. }
  510. int hints = 0;
  511. int audioIns = 0;
  512. int audioOuts = 0;
  513. int audioTotal = 0;
  514. int midiIns = 0;
  515. int midiOuts = 0;
  516. int midiTotal = 0;
  517. int parametersIns = 0;
  518. int parametersOuts = 0;
  519. int parametersTotal = 0;
  520. for (uint32_t j=0; j < rdf_descriptor->PortCount; j++)
  521. {
  522. const LV2_RDF_Port* const Port = &rdf_descriptor->Ports[j];
  523. if (LV2_IS_PORT_AUDIO(Port->Type))
  524. {
  525. if (LV2_IS_PORT_INPUT(Port->Type))
  526. audioIns += 1;
  527. else if (LV2_IS_PORT_OUTPUT(Port->Type))
  528. audioOuts += 1;
  529. audioTotal += 1;
  530. }
  531. else if (LV2_IS_PORT_CONTROL(Port->Type))
  532. {
  533. if (LV2_IS_PORT_INPUT(Port->Type))
  534. parametersIns += 1;
  535. else if (LV2_IS_PORT_OUTPUT(Port->Type) && ! LV2_IS_PORT_LATENCY(Port->Designation))
  536. parametersOuts += 1;
  537. parametersTotal += 1;
  538. }
  539. else if (Port->Type & LV2_PORT_SUPPORTS_MIDI_EVENT)
  540. {
  541. if (LV2_IS_PORT_INPUT(Port->Type))
  542. midiIns += 1;
  543. else if (LV2_IS_PORT_OUTPUT(Port->Type))
  544. midiOuts += 1;
  545. midiTotal += 1;
  546. }
  547. }
  548. if (rdf_descriptor->Type & LV2_CLASS_INSTRUMENT)
  549. hints |= PLUGIN_IS_SYNTH;
  550. if (rdf_descriptor->UICount > 0)
  551. hints |= PLUGIN_HAS_GUI;
  552. DISCOVERY_OUT("init", "-----------");
  553. DISCOVERY_OUT("name", rdf_descriptor->Name);
  554. DISCOVERY_OUT("label", rdf_descriptor->URI);
  555. if (rdf_descriptor->Author)
  556. DISCOVERY_OUT("maker", rdf_descriptor->Author);
  557. if (rdf_descriptor->License)
  558. DISCOVERY_OUT("copyright", rdf_descriptor->License);
  559. DISCOVERY_OUT("unique_id", rdf_descriptor->UniqueID);
  560. DISCOVERY_OUT("hints", hints);
  561. DISCOVERY_OUT("audio.ins", audioIns);
  562. DISCOVERY_OUT("audio.outs", audioOuts);
  563. DISCOVERY_OUT("audio.total", audioTotal);
  564. DISCOVERY_OUT("midi.ins", midiIns);
  565. DISCOVERY_OUT("midi.outs", midiOuts);
  566. DISCOVERY_OUT("midi.total", midiTotal);
  567. DISCOVERY_OUT("parameters.ins", parametersIns);
  568. DISCOVERY_OUT("parameters.outs", parametersOuts);
  569. DISCOVERY_OUT("parameters.total", parametersTotal);
  570. DISCOVERY_OUT("build", BINARY_NATIVE);
  571. DISCOVERY_OUT("end", "------------");
  572. }
  573. }
  574. void do_vst_check(void* const lib_handle, const bool init)
  575. {
  576. VST_Function vstfn = (VST_Function)lib_symbol(lib_handle, "VSTPluginMain");
  577. if (! vstfn)
  578. vstfn = (VST_Function)lib_symbol(lib_handle, "main");
  579. if (! vstfn)
  580. {
  581. DISCOVERY_OUT("error", "Not a VST plugin");
  582. return;
  583. }
  584. AEffect* const effect = vstfn(VstHostCallback);
  585. if (! (effect && effect->magic == kEffectMagic))
  586. {
  587. DISCOVERY_OUT("error", "Failed to init VST plugin");
  588. return;
  589. }
  590. const char* cName;
  591. const char* cProduct;
  592. const char* cVendor;
  593. char strBuf[255] = { 0 };
  594. effect->dispatcher(effect, effGetEffectName, 0, 0, strBuf, 0.0f);
  595. cName = strdup((strBuf[0] != 0) ? strBuf : "");
  596. strBuf[0] = 0;
  597. effect->dispatcher(effect, effGetProductString, 0, 0, strBuf, 0.0f);
  598. cProduct = strdup((strBuf[0] != 0) ? strBuf : "");
  599. strBuf[0] = 0;
  600. effect->dispatcher(effect, effGetVendorString, 0, 0, strBuf, 0.0f);
  601. cVendor = strdup((strBuf[0] != 0) ? strBuf : "");
  602. VstCurrentUniqueId = effect->uniqueID;
  603. intptr_t VstCategory = effect->dispatcher(effect, effGetPlugCategory, 0, 0, nullptr, 0.0f);
  604. // only init if required
  605. if (init || VstCategory == kPlugCategShell)
  606. effect->dispatcher(effect, effOpen, 0, 0, nullptr, 0.0f);
  607. while (true)
  608. {
  609. int hints = 0;
  610. int audioIns = effect->numInputs;
  611. int audioOuts = effect->numOutputs;
  612. int audioTotal = audioIns + audioOuts;
  613. int midiIns = 0;
  614. int midiOuts = 0;
  615. int midiTotal = 0;
  616. int parametersIns = effect->numParams;
  617. int parametersTotal = parametersIns;
  618. int programsTotal = effect->numPrograms;
  619. if (effect->flags & effFlagsHasEditor)
  620. hints |= PLUGIN_HAS_GUI;
  621. if (effect->flags & effFlagsIsSynth)
  622. hints |= PLUGIN_IS_SYNTH;
  623. if (VstPluginCanDo(effect, "receiveVstEvents") || VstPluginCanDo(effect, "receiveVstMidiEvent") || (effect->flags & effFlagsIsSynth) > 0)
  624. midiIns = 1;
  625. if (VstPluginCanDo(effect, "sendVstEvents") || VstPluginCanDo(effect, "sendVstMidiEvent"))
  626. midiOuts = 1;
  627. midiTotal = midiIns + midiOuts;
  628. // -----------------------------------------------------------------------
  629. // start crash-free plugin test
  630. if (init)
  631. {
  632. float** bufferAudioIn = new float* [audioIns];
  633. for (int j=0; j < audioIns; j++)
  634. {
  635. bufferAudioIn[j] = new float [bufferSize];
  636. memset(bufferAudioIn[j], 0, sizeof(float)*bufferSize);
  637. }
  638. float** bufferAudioOut = new float* [audioOuts];
  639. for (int j=0; j < audioOuts; j++)
  640. {
  641. bufferAudioOut[j] = new float [bufferSize];
  642. memset(bufferAudioOut[j], 0, sizeof(float)*bufferSize);
  643. }
  644. struct {
  645. int32_t numEvents;
  646. intptr_t reserved;
  647. VstEvent* data[2];
  648. } events;
  649. VstMidiEvent midiEvents[2];
  650. memset(midiEvents, 0, sizeof(VstMidiEvent)*2);
  651. midiEvents[0].type = kVstMidiType;
  652. midiEvents[0].byteSize = sizeof(VstMidiEvent);
  653. midiEvents[0].midiData[0] = 0x90;
  654. midiEvents[0].midiData[1] = 64;
  655. midiEvents[0].midiData[2] = 100;
  656. midiEvents[1].type = kVstMidiType;
  657. midiEvents[1].byteSize = sizeof(VstMidiEvent);
  658. midiEvents[1].midiData[0] = 0x80;
  659. midiEvents[1].midiData[1] = 64;
  660. midiEvents[1].deltaFrames = bufferSize/2;
  661. events.numEvents = 2;
  662. events.reserved = 0;
  663. events.data[0] = (VstEvent*)&midiEvents[0];
  664. events.data[1] = (VstEvent*)&midiEvents[1];
  665. #if ! VST_FORCE_DEPRECATED
  666. effect->dispatcher(effect, effSetBlockSizeAndSampleRate, 0, bufferSize, nullptr, sampleRate);
  667. #endif
  668. effect->dispatcher(effect, effSetBlockSize, 0, bufferSize, nullptr, 0.0f);
  669. effect->dispatcher(effect, effSetSampleRate, 0, 0, nullptr, sampleRate);
  670. effect->dispatcher(effect, effSetProcessPrecision, 0, kVstProcessPrecision32, nullptr, 0.0f);
  671. effect->dispatcher(effect, effMainsChanged, 0, 1, nullptr, 0.0f);
  672. effect->dispatcher(effect, effStartProcess, 0, 0, nullptr, 0.0f);
  673. if (midiIns > 0)
  674. effect->dispatcher(effect, effProcessEvents, 0, 0, &events, 0.0f);
  675. if (effect->processReplacing != effect->process && (effect->flags & effFlagsCanReplacing) > 0)
  676. effect->processReplacing(effect, bufferAudioIn, bufferAudioOut, bufferSize);
  677. #if ! VST_FORCE_DEPRECATED
  678. else
  679. effect->process(effect, bufferAudioIn, bufferAudioOut, bufferSize);
  680. #endif
  681. effect->dispatcher(effect, effStopProcess, 0, 0, nullptr, 0.0f);
  682. effect->dispatcher(effect, effMainsChanged, 0, 0, nullptr, 0.0f);
  683. for (int j=0; j < audioIns; j++)
  684. delete[] bufferAudioIn[j];
  685. for (int j=0; j < audioOuts; j++)
  686. delete[] bufferAudioOut[j];
  687. delete[] bufferAudioIn;
  688. delete[] bufferAudioOut;
  689. }
  690. // end crash-free plugin test
  691. // -----------------------------------------------------------------------
  692. DISCOVERY_OUT("init", "-----------");
  693. DISCOVERY_OUT("name", cName);
  694. DISCOVERY_OUT("label", cProduct);
  695. DISCOVERY_OUT("maker", cVendor);
  696. DISCOVERY_OUT("copyright", cVendor);
  697. DISCOVERY_OUT("unique_id", VstCurrentUniqueId);
  698. DISCOVERY_OUT("hints", hints);
  699. DISCOVERY_OUT("audio.ins", audioIns);
  700. DISCOVERY_OUT("audio.outs", audioOuts);
  701. DISCOVERY_OUT("audio.total", audioTotal);
  702. DISCOVERY_OUT("midi.ins", midiIns);
  703. DISCOVERY_OUT("midi.outs", midiOuts);
  704. DISCOVERY_OUT("midi.total", midiTotal);
  705. DISCOVERY_OUT("parameters.ins", parametersIns);
  706. DISCOVERY_OUT("parameters.total", parametersTotal);
  707. DISCOVERY_OUT("programs.total", programsTotal);
  708. DISCOVERY_OUT("build", BINARY_NATIVE);
  709. DISCOVERY_OUT("end", "------------");
  710. if (VstCategory != kPlugCategShell)
  711. break;
  712. strBuf[0] = 0;
  713. VstCurrentUniqueId = effect->dispatcher(effect, effShellGetNextPlugin, 0, 0, strBuf, 0.0f);
  714. if (VstCurrentUniqueId != 0)
  715. {
  716. free((void*)cName);
  717. cName = strdup((strBuf[0] != 0) ? strBuf : "");
  718. }
  719. else
  720. break;
  721. }
  722. // only close if required
  723. if (init || VstCategory == kPlugCategShell)
  724. effect->dispatcher(effect, effClose, 0, 0, nullptr, 0.0f);
  725. free((void*)cName);
  726. free((void*)cProduct);
  727. free((void*)cVendor);
  728. }
  729. void do_fluidsynth_check(const char* const filename, const bool init)
  730. {
  731. #ifdef WANT_FLUIDSYNTH
  732. if (! fluid_is_soundfont(filename))
  733. {
  734. DISCOVERY_OUT("error", "Not a SF2 file");
  735. return;
  736. }
  737. int programs = 0;
  738. if (init)
  739. {
  740. fluid_settings_t* const f_settings = new_fluid_settings();
  741. fluid_synth_t* const f_synth = new_fluid_synth(f_settings);
  742. const int f_id = fluid_synth_sfload(f_synth, filename, 0);
  743. if (f_id < 0)
  744. {
  745. DISCOVERY_OUT("error", "Failed to load SF2 file");
  746. return;
  747. }
  748. fluid_sfont_t* f_sfont;
  749. fluid_preset_t f_preset;
  750. f_sfont = fluid_synth_get_sfont_by_id(f_synth, f_id);
  751. f_sfont->iteration_start(f_sfont);
  752. while (f_sfont->iteration_next(f_sfont, &f_preset))
  753. programs += 1;
  754. delete_fluid_synth(f_synth);
  755. delete_fluid_settings(f_settings);
  756. }
  757. DISCOVERY_OUT("init", "-----------");
  758. DISCOVERY_OUT("name", "");
  759. DISCOVERY_OUT("label", "");
  760. DISCOVERY_OUT("maker", "");
  761. DISCOVERY_OUT("copyright", "");
  762. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  763. DISCOVERY_OUT("audio.outs", 2);
  764. DISCOVERY_OUT("audio.total", 2);
  765. DISCOVERY_OUT("midi.ins", 1);
  766. DISCOVERY_OUT("midi.total", 1);
  767. DISCOVERY_OUT("programs.total", programs);
  768. DISCOVERY_OUT("parameters.ins", 13); // defined in Carla
  769. DISCOVERY_OUT("parameters.outs", 1);
  770. DISCOVERY_OUT("parameters.total", 14);
  771. DISCOVERY_OUT("build", BINARY_NATIVE);
  772. DISCOVERY_OUT("end", "------------");
  773. #else
  774. DISCOVERY_OUT("error", "SF2 support not available");
  775. Q_UNUSED(filename);
  776. Q_UNUSED(init);
  777. #endif
  778. }
  779. void do_linuxsampler_check(const char* const filename, const char* const stype, const bool init)
  780. {
  781. #ifdef WANT_LINUXSAMPLER
  782. const QFileInfo file(filename);
  783. if (! file.exists())
  784. {
  785. DISCOVERY_OUT("error", "Requested file does not exist");
  786. return;
  787. }
  788. if (! file.isFile())
  789. {
  790. DISCOVERY_OUT("error", "Requested file is not valid");
  791. return;
  792. }
  793. if (! file.isReadable())
  794. {
  795. DISCOVERY_OUT("error", "Requested file is not readable");
  796. return;
  797. }
  798. using namespace LinuxSampler;
  799. class LinuxSamplerScopedEngine {
  800. public:
  801. LinuxSamplerScopedEngine(const char* const filename, const char* const stype)
  802. {
  803. try {
  804. engine = EngineFactory::Create(stype);
  805. }
  806. catch (const Exception& e)
  807. {
  808. DISCOVERY_OUT("error", e.what());
  809. return;
  810. }
  811. ins = engine->GetInstrumentManager();
  812. if (! ins)
  813. {
  814. DISCOVERY_OUT("error", "Failed to get LinuxSampeler instrument manager");
  815. return;
  816. }
  817. std::vector<InstrumentManager::instrument_id_t> ids;
  818. try {
  819. ids = ins->GetInstrumentFileContent(filename);
  820. }
  821. catch (const Exception& e)
  822. {
  823. DISCOVERY_OUT("error", e.what());
  824. return;
  825. }
  826. if (ids.size() > 0)
  827. {
  828. InstrumentManager::instrument_info_t info = ins->GetInstrumentInfo(ids[0]);
  829. outputInfo(&info, ids.size());
  830. }
  831. }
  832. ~LinuxSamplerScopedEngine()
  833. {
  834. if (engine)
  835. EngineFactory::Destroy(engine);
  836. }
  837. static void outputInfo(InstrumentManager::instrument_info_t* const info, const int programs)
  838. {
  839. DISCOVERY_OUT("init", "-----------");
  840. if (info)
  841. {
  842. DISCOVERY_OUT("name", info->InstrumentName);
  843. DISCOVERY_OUT("label", info->Product);
  844. DISCOVERY_OUT("maker", info->Artists);
  845. DISCOVERY_OUT("copyright", info->Artists);
  846. }
  847. DISCOVERY_OUT("hints", PLUGIN_IS_SYNTH);
  848. DISCOVERY_OUT("audio.outs", 2);
  849. DISCOVERY_OUT("audio.total", 2);
  850. DISCOVERY_OUT("midi.ins", 1);
  851. DISCOVERY_OUT("midi.total", 1);
  852. DISCOVERY_OUT("programs.total", programs);
  853. //DISCOVERY_OUT("parameters.ins", 13); // defined in Carla - TODO
  854. //DISCOVERY_OUT("parameters.outs", 1);
  855. //DISCOVERY_OUT("parameters.total", 14);
  856. DISCOVERY_OUT("build", BINARY_NATIVE);
  857. DISCOVERY_OUT("end", "------------");
  858. }
  859. private:
  860. Engine* engine;
  861. InstrumentManager* ins;
  862. };
  863. if (init)
  864. const LinuxSamplerScopedEngine engine(filename, stype);
  865. else
  866. LinuxSamplerScopedEngine::outputInfo(nullptr, 0);
  867. #else
  868. DISCOVERY_OUT("error", stype << " support not available");
  869. Q_UNUSED(filename);
  870. Q_UNUSED(init);
  871. #endif
  872. }
  873. // ------------------------------ main entry point ------------------------------
  874. int main(int argc, char* argv[])
  875. {
  876. if (argc != 3)
  877. {
  878. qWarning("usage: %s <type> </path/to/plugin>", argv[0]);
  879. return 1;
  880. }
  881. const char* const stype = argv[1];
  882. const char* const filename = argv[2];
  883. bool openLib;
  884. PluginType type;
  885. void* handle = nullptr;
  886. if (strcmp(stype, "LADSPA") == 0)
  887. {
  888. openLib = true;
  889. type = PLUGIN_LADSPA;
  890. }
  891. else if (strcmp(stype, "DSSI") == 0)
  892. {
  893. openLib = true;
  894. type = PLUGIN_DSSI;
  895. }
  896. else if (strcmp(stype, "LV2") == 0)
  897. {
  898. openLib = false;
  899. type = PLUGIN_LV2;
  900. }
  901. else if (strcmp(stype, "VST") == 0)
  902. {
  903. openLib = true;
  904. type = PLUGIN_VST;
  905. }
  906. else if (strcmp(stype, "GIG") == 0)
  907. {
  908. openLib = false;
  909. type = PLUGIN_GIG;
  910. }
  911. else if (strcmp(stype, "SF2") == 0)
  912. {
  913. openLib = false;
  914. type = PLUGIN_SF2;
  915. }
  916. else if (strcmp(stype, "SFZ") == 0)
  917. {
  918. openLib = false;
  919. type = PLUGIN_SFZ;
  920. }
  921. else
  922. {
  923. DISCOVERY_OUT("error", "Invalid plugin type");
  924. return 1;
  925. }
  926. if (openLib)
  927. {
  928. handle = lib_open(filename);
  929. if (! handle)
  930. {
  931. print_lib_error(filename);
  932. return 1;
  933. }
  934. }
  935. bool doInit = ! QString(filename).endsWith("dssi-vst.so", Qt::CaseInsensitive);
  936. if (doInit && getenv("CARLA_DISCOVERY_NO_PROCESSING_CHECKS"))
  937. doInit = false;
  938. switch (type)
  939. {
  940. case PLUGIN_LADSPA:
  941. do_ladspa_check(handle, doInit);
  942. break;
  943. case PLUGIN_DSSI:
  944. do_dssi_check(handle, doInit);
  945. break;
  946. case PLUGIN_LV2:
  947. do_lv2_check(filename, doInit);
  948. break;
  949. case PLUGIN_VST:
  950. do_vst_check(handle, doInit);
  951. break;
  952. case PLUGIN_GIG:
  953. do_linuxsampler_check(filename, "gig", doInit);
  954. break;
  955. case PLUGIN_SF2:
  956. do_fluidsynth_check(filename, doInit);
  957. break;
  958. case PLUGIN_SFZ:
  959. do_linuxsampler_check(filename, "sfz", doInit);
  960. break;
  961. default:
  962. break;
  963. }
  964. if (openLib)
  965. lib_close(handle);
  966. return 0;
  967. }