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.

766 lines
23KB

  1. /*
  2. * Carla Plugin Engine (Native)
  3. * Copyright (C) 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 GPL.txt file
  16. */
  17. #ifndef BUILD_BRIDGE
  18. #include "CarlaEngineInternal.hpp"
  19. #include "CarlaStateUtils.hpp"
  20. #include "CarlaNative.hpp"
  21. #ifdef WANT_LV2
  22. # include "lv2/lv2.h"
  23. # include "lv2/atom.h"
  24. struct Lv2HostDescriptor {
  25. uint32_t bufferSize;
  26. double sampleRate;
  27. TimeInfo timeInfo;
  28. float* audioPorts[4];
  29. LV2_Atom_Sequence* atomPort;
  30. Lv2HostDescriptor()
  31. : bufferSize(0),
  32. sampleRate(0.0),
  33. audioPorts{nullptr},
  34. atomPort(nullptr) {}
  35. };
  36. #else
  37. struct Lv2HostDescriptor;
  38. #endif
  39. #include <QtCore/QTextStream>
  40. CARLA_BACKEND_START_NAMESPACE
  41. // -----------------------------------------------------------------------
  42. class CarlaEngineNative : public PluginDescriptorClass,
  43. public CarlaEngine
  44. {
  45. public:
  46. CarlaEngineNative(const HostDescriptor* const host, Lv2HostDescriptor* const lv2Host = nullptr)
  47. : PluginDescriptorClass(host),
  48. CarlaEngine(),
  49. fLv2Host(lv2Host)
  50. {
  51. carla_debug("CarlaEngineNative::CarlaEngineNative()");
  52. // set-up engine
  53. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  54. fOptions.transportMode = TRANSPORT_MODE_PLUGIN;
  55. fOptions.forceStereo = true;
  56. fOptions.preferPluginBridges = false;
  57. fOptions.preferUiBridges = false;
  58. init("Carla-Plugin");
  59. }
  60. ~CarlaEngineNative() override
  61. {
  62. carla_debug("CarlaEngineNative::~CarlaEngineNative()");
  63. setAboutToClose();
  64. removeAllPlugins();
  65. close();
  66. #ifdef WANT_LV2
  67. if (fLv2Host != nullptr)
  68. {
  69. delete fLv2Host;
  70. delete hostHandle();
  71. }
  72. #endif
  73. }
  74. protected:
  75. // -------------------------------------
  76. // CarlaEngine virtual calls
  77. bool init(const char* const clientName) override
  78. {
  79. carla_debug("CarlaEngineNative::init(\"%s\")", clientName);
  80. fBufferSize = PluginDescriptorClass::getBufferSize();
  81. fSampleRate = PluginDescriptorClass::getSampleRate();
  82. CarlaEngine::init(clientName);
  83. return true;
  84. }
  85. bool close() override
  86. {
  87. carla_debug("CarlaEngineNative::close()");
  88. proccessPendingEvents();
  89. return CarlaEngine::close();
  90. }
  91. bool isRunning() const override
  92. {
  93. return true;
  94. }
  95. bool isOffline() const override
  96. {
  97. return false;
  98. }
  99. EngineType type() const override
  100. {
  101. return kEngineTypePlugin;
  102. }
  103. // -------------------------------------------------------------------
  104. // Plugin parameter calls
  105. uint32_t getParameterCount() override
  106. {
  107. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  108. return 0;
  109. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  110. if (plugin == nullptr || ! plugin->enabled())
  111. return 0;
  112. return kData->plugins[0].plugin->parameterCount();
  113. }
  114. const Parameter* getParameterInfo(const uint32_t index) override
  115. {
  116. if (index >= getParameterCount())
  117. return nullptr;
  118. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  119. if (plugin == nullptr || ! plugin->enabled())
  120. return nullptr;
  121. static ::Parameter param;
  122. static char strBufName[STR_MAX+1];
  123. static char strBufUnit[STR_MAX+1];
  124. const ParameterData& paramData(plugin->parameterData(index));
  125. const ParameterRanges& paramRanges(plugin->parameterRanges(index));
  126. plugin->getParameterName(index, strBufName);
  127. plugin->getParameterUnit(index, strBufUnit);
  128. unsigned int hints = 0x0;
  129. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  130. hints |= ::PARAMETER_IS_BOOLEAN;
  131. if (paramData.hints & PARAMETER_IS_INTEGER)
  132. hints |= ::PARAMETER_IS_INTEGER;
  133. if (paramData.hints & PARAMETER_IS_LOGARITHMIC)
  134. hints |= ::PARAMETER_IS_LOGARITHMIC;
  135. if (paramData.hints & PARAMETER_IS_AUTOMABLE)
  136. hints |= ::PARAMETER_IS_AUTOMABLE;
  137. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  138. hints |= ::PARAMETER_USES_SAMPLE_RATE;
  139. if (paramData.hints & PARAMETER_USES_SCALEPOINTS)
  140. hints |= ::PARAMETER_USES_SCALEPOINTS;
  141. if (paramData.hints & PARAMETER_USES_CUSTOM_TEXT)
  142. hints |= ::PARAMETER_USES_CUSTOM_TEXT;
  143. if (paramData.type == PARAMETER_INPUT || paramData.type == PARAMETER_OUTPUT)
  144. {
  145. if (paramData.hints & PARAMETER_IS_ENABLED)
  146. hints |= ::PARAMETER_IS_ENABLED;
  147. if (paramData.type == PARAMETER_OUTPUT)
  148. hints |= ::PARAMETER_IS_OUTPUT;
  149. }
  150. param.hints = static_cast< ::ParameterHints>(hints);
  151. param.name = strBufName;
  152. param.unit = strBufUnit;
  153. param.ranges.def = paramRanges.def;
  154. param.ranges.min = paramRanges.min;
  155. param.ranges.max = paramRanges.max;
  156. param.ranges.step = paramRanges.step;
  157. param.ranges.stepSmall = paramRanges.stepSmall;
  158. param.ranges.stepLarge = paramRanges.stepLarge;
  159. param.scalePointCount = 0; // TODO
  160. param.scalePoints = nullptr;
  161. return &param;
  162. }
  163. float getParameterValue(const uint32_t index) override
  164. {
  165. if (index >= getParameterCount())
  166. return 0.0f;
  167. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  168. if (plugin == nullptr || ! plugin->enabled())
  169. return 0.0f;
  170. return plugin->getParameterValue(index);
  171. }
  172. const char* getParameterText(const uint32_t index) override
  173. {
  174. if (index >= getParameterCount())
  175. return nullptr;
  176. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  177. if (plugin == nullptr || ! plugin->enabled())
  178. return nullptr;
  179. static char strBuf[STR_MAX+1];
  180. plugin->getParameterText(index, strBuf);
  181. return strBuf;
  182. }
  183. // -------------------------------------------------------------------
  184. // Plugin midi-program calls
  185. uint32_t getMidiProgramCount() override
  186. {
  187. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  188. return 0;
  189. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  190. if (plugin == nullptr || ! plugin->enabled())
  191. return 0.0f;
  192. return plugin->midiProgramCount();
  193. }
  194. const MidiProgram* getMidiProgramInfo(const uint32_t index) override
  195. {
  196. if (index >= getMidiProgramCount())
  197. return nullptr;
  198. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  199. if (plugin == nullptr || ! plugin->enabled())
  200. return nullptr;
  201. static ::MidiProgram midiProg;
  202. {
  203. const MidiProgramData& midiProgData(plugin->midiProgramData(index));
  204. midiProg.bank = midiProgData.bank;
  205. midiProg.program = midiProgData.program;
  206. midiProg.name = midiProgData.name;
  207. }
  208. return &midiProg;
  209. }
  210. // -------------------------------------------------------------------
  211. // Plugin state calls
  212. void setParameterValue(const uint32_t index, const float value) override
  213. {
  214. if (index >= getParameterCount())
  215. return;
  216. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  217. if (plugin == nullptr || ! plugin->enabled())
  218. return;
  219. plugin->setParameterValue(index, value, false, false, false);
  220. }
  221. void setMidiProgram(const uint8_t, const uint32_t bank, const uint32_t program) override
  222. {
  223. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  224. return;
  225. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  226. if (plugin == nullptr || ! plugin->enabled())
  227. return;
  228. plugin->setMidiProgramById(bank, program, false, false, false);
  229. }
  230. void setCustomData(const char* const key, const char* const value) override
  231. {
  232. CARLA_ASSERT(key != nullptr);
  233. CARLA_ASSERT(value != nullptr);
  234. return;
  235. // TODO
  236. // unused
  237. (void)key;
  238. (void)value;
  239. }
  240. // -------------------------------------------------------------------
  241. // Plugin process calls
  242. void activate() override
  243. {
  244. for (uint32_t i=0; i < kData->curPluginCount; ++i)
  245. {
  246. CarlaPlugin* const plugin(kData->plugins[i].plugin);
  247. if (plugin == nullptr || ! plugin->enabled())
  248. continue;
  249. plugin->setActive(true, true, false);
  250. }
  251. }
  252. void deactivate() override
  253. {
  254. for (uint32_t i=0; i < kData->curPluginCount; ++i)
  255. {
  256. CarlaPlugin* const plugin(kData->plugins[i].plugin);
  257. if (plugin == nullptr || ! plugin->enabled())
  258. continue;
  259. plugin->setActive(false, true, false);
  260. }
  261. // just in case
  262. proccessPendingEvents();
  263. }
  264. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const ::MidiEvent* const midiEvents) override
  265. {
  266. if (kData->curPluginCount == 0)
  267. {
  268. carla_zeroFloat(outBuffer[0], frames);
  269. carla_zeroFloat(outBuffer[1], frames);
  270. return CarlaEngine::proccessPendingEvents();
  271. }
  272. // ---------------------------------------------------------------
  273. // Time Info
  274. const ::TimeInfo* timeInfo(PluginDescriptorClass::getTimeInfo());
  275. fTimeInfo.playing = timeInfo->playing;
  276. fTimeInfo.frame = timeInfo->frame;
  277. fTimeInfo.usecs = timeInfo->usecs;
  278. fTimeInfo.valid = 0x0;
  279. if (timeInfo->bbt.valid)
  280. {
  281. fTimeInfo.valid |= EngineTimeInfo::ValidBBT;
  282. fTimeInfo.bbt.bar = timeInfo->bbt.bar;
  283. fTimeInfo.bbt.beat = timeInfo->bbt.beat;
  284. fTimeInfo.bbt.tick = timeInfo->bbt.tick;
  285. fTimeInfo.bbt.barStartTick = timeInfo->bbt.barStartTick;
  286. fTimeInfo.bbt.beatsPerBar = timeInfo->bbt.beatsPerBar;
  287. fTimeInfo.bbt.beatType = timeInfo->bbt.beatType;
  288. fTimeInfo.bbt.ticksPerBeat = timeInfo->bbt.ticksPerBeat;
  289. fTimeInfo.bbt.beatsPerMinute = timeInfo->bbt.beatsPerMinute;
  290. }
  291. // ---------------------------------------------------------------
  292. // initialize input events
  293. carla_zeroStruct<EngineEvent>(kData->bufEvent.in, INTERNAL_EVENT_COUNT);
  294. {
  295. uint32_t engineEventIndex = 0;
  296. for (uint32_t i=0; i < midiEventCount && engineEventIndex < INTERNAL_EVENT_COUNT; ++i)
  297. {
  298. const ::MidiEvent& midiEvent(midiEvents[i]);
  299. if (midiEvent.size > 4)
  300. continue;
  301. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  302. const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  303. // we don't want some events
  304. if (status == MIDI_STATUS_PROGRAM_CHANGE)
  305. continue;
  306. // handle note/sound off properly
  307. if (status == MIDI_STATUS_CONTROL_CHANGE)
  308. {
  309. const uint8_t control = midiEvent.data[1];
  310. if (MIDI_IS_CONTROL_BANK_SELECT(control))
  311. continue;
  312. if (control == MIDI_CONTROL_ALL_SOUND_OFF || control == MIDI_CONTROL_ALL_NOTES_OFF)
  313. {
  314. EngineEvent& engineEvent(kData->bufEvent.in[engineEventIndex++]);
  315. engineEvent.clear();
  316. engineEvent.type = kEngineEventTypeControl;
  317. engineEvent.time = midiEvent.time;
  318. engineEvent.channel = channel;
  319. engineEvent.ctrl.type = (control == MIDI_CONTROL_ALL_SOUND_OFF) ? kEngineControlEventTypeAllSoundOff : kEngineControlEventTypeAllNotesOff;
  320. engineEvent.ctrl.param = 0;
  321. engineEvent.ctrl.value = 0.0f;
  322. continue;
  323. }
  324. }
  325. EngineEvent& engineEvent(kData->bufEvent.in[engineEventIndex++]);
  326. engineEvent.clear();
  327. engineEvent.type = kEngineEventTypeMidi;
  328. engineEvent.time = midiEvent.time;
  329. engineEvent.channel = channel;
  330. engineEvent.midi.data[0] = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  331. engineEvent.midi.data[1] = midiEvent.data[1];
  332. engineEvent.midi.data[2] = midiEvent.data[2];
  333. engineEvent.midi.data[3] = midiEvent.data[3];
  334. engineEvent.midi.size = midiEvent.size;
  335. }
  336. }
  337. // ---------------------------------------------------------------
  338. // create audio buffers
  339. float* inBuf[2] = { inBuffer[0], inBuffer[1] };
  340. float* outBuf[2] = { outBuffer[0], outBuffer[1] };
  341. // ---------------------------------------------------------------
  342. // process
  343. CarlaEngine::processRack(inBuf, outBuf, frames);
  344. CarlaEngine::proccessPendingEvents();
  345. }
  346. // -------------------------------------------------------------------
  347. // Plugin UI calls
  348. void uiShow(const bool show) override
  349. {
  350. return;
  351. // TODO
  352. // unused
  353. (void)show;
  354. }
  355. void uiIdle() override
  356. {
  357. CarlaEngine::idle();
  358. }
  359. void uiSetParameterValue(const uint32_t index, const float value) override
  360. {
  361. if (index >= getParameterCount())
  362. return;
  363. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  364. if (plugin == nullptr || ! plugin->enabled())
  365. return;
  366. plugin->uiParameterChange(index, value);
  367. }
  368. void uiSetMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  369. {
  370. return;
  371. // TODO
  372. // unused
  373. (void)channel;
  374. (void)bank;
  375. (void)program;
  376. }
  377. void uiSetCustomData(const char* const key, const char* const value) override
  378. {
  379. CARLA_ASSERT(key != nullptr);
  380. CARLA_ASSERT(value != nullptr);
  381. return;
  382. // TODO
  383. // unused
  384. (void)key;
  385. (void)value;
  386. }
  387. // -------------------------------------------------------------------
  388. // Plugin state calls
  389. char* getState() override
  390. {
  391. QString string;
  392. QTextStream out(&string);
  393. out << "<?xml version='1.0' encoding='UTF-8'?>\n";
  394. out << "<!DOCTYPE CARLA-PROJECT>\n";
  395. out << "<CARLA-PROJECT VERSION='1.0'>\n";
  396. bool firstPlugin = true;
  397. char strBuf[STR_MAX+1];
  398. for (unsigned int i=0; i < kData->curPluginCount; ++i)
  399. {
  400. CarlaPlugin* const plugin = kData->plugins[i].plugin;
  401. if (plugin != nullptr && plugin->enabled())
  402. {
  403. if (! firstPlugin)
  404. out << "\n";
  405. plugin->getRealName(strBuf);
  406. if (*strBuf != 0)
  407. out << QString(" <!-- %1 -->\n").arg(xmlSafeString(strBuf, true));
  408. out << " <Plugin>\n";
  409. out << getXMLFromSaveState(plugin->getSaveState());
  410. out << " </Plugin>\n";
  411. firstPlugin = false;
  412. }
  413. }
  414. out << "</CARLA-PROJECT>\n";
  415. return strdup(string.toUtf8().constData());
  416. }
  417. void setState(const char* const data) override
  418. {
  419. QDomDocument xml;
  420. xml.setContent(QString(data));
  421. QDomNode xmlNode(xml.documentElement());
  422. if (xmlNode.toElement().tagName() != "CARLA-PROJECT")
  423. {
  424. carla_stderr2("Not a valid Carla project");
  425. return;
  426. }
  427. QDomNode node(xmlNode.firstChild());
  428. while (! node.isNull())
  429. {
  430. if (node.toElement().tagName() == "Plugin")
  431. {
  432. const SaveState& saveState(getSaveStateDictFromXML(node));
  433. CARLA_ASSERT(saveState.type != nullptr);
  434. if (saveState.type == nullptr)
  435. continue;
  436. const void* extraStuff = nullptr;
  437. // FIXME
  438. //if (std::strcmp(saveState.type, "DSSI") == 0)
  439. // extraStuff = findDSSIGUI(saveState.binary, saveState.label);
  440. // TODO - proper find&load plugins
  441. if (addPlugin(getPluginTypeFromString(saveState.type), saveState.binary, saveState.name, saveState.label, extraStuff))
  442. {
  443. if (CarlaPlugin* plugin = getPlugin(kData->curPluginCount-1))
  444. plugin->loadSaveState(saveState);
  445. }
  446. }
  447. node = node.nextSibling();
  448. }
  449. }
  450. // -------------------------------------------------------------------
  451. #ifdef WANT_LV2
  452. Lv2HostDescriptor* const fLv2Host;
  453. // -------------------------------------------------------------------
  454. public:
  455. #define handlePtr ((Lv2HostDescriptor*)handle)
  456. static uint32_t lv2host_get_buffer_size(HostHandle handle)
  457. {
  458. return handlePtr->bufferSize;
  459. }
  460. static double lv2host_get_sample_rate(HostHandle handle)
  461. {
  462. return handlePtr->sampleRate;
  463. }
  464. static const TimeInfo* lv2host_get_time_info(HostHandle handle)
  465. {
  466. return &handlePtr->timeInfo;
  467. }
  468. static bool lv2host_write_midi_event(HostHandle, const MidiEvent*)
  469. {
  470. // MIDI Out not supported yet
  471. return false;
  472. }
  473. static void lv2host_ui_parameter_changed(HostHandle, uint32_t, float) {}
  474. static void lv2host_ui_midi_program_changed(HostHandle, uint8_t, uint32_t, uint32_t) {}
  475. static void lv2host_ui_custom_data_changed(HostHandle, const char*, const char*) {}
  476. static void lv2host_ui_closed(HostHandle) {}
  477. static const char* lv2host_ui_open_file(HostHandle, bool, const char*, const char*) { return nullptr; }
  478. static const char* lv2host_ui_save_file(HostHandle, bool, const char*, const char*) { return nullptr; }
  479. static intptr_t lv2host_dispatcher(HostHandle, HostDispatcherOpcode, int32_t, intptr_t, void*) { return 0; }
  480. #undef handlePtr
  481. // -------------------------------------------------------------------
  482. #define handlePtr ((CarlaEngineNative*)handle)
  483. static LV2_Handle lv2_instantiate(const LV2_Descriptor*, double sampleRate, const char*, const LV2_Feature* const* /*features*/)
  484. {
  485. Lv2HostDescriptor* const lv2Host(new Lv2HostDescriptor());
  486. lv2Host->bufferSize = 1024; // TODO
  487. lv2Host->sampleRate = sampleRate;
  488. lv2Host->timeInfo.frame = 0;
  489. lv2Host->timeInfo.usecs = 0;
  490. lv2Host->timeInfo.playing = false;
  491. lv2Host->timeInfo.bbt.valid = false;
  492. HostDescriptor* const host(new HostDescriptor);
  493. host->handle = lv2Host;
  494. host->ui_name = nullptr;
  495. host->get_buffer_size = lv2host_get_buffer_size;
  496. host->get_sample_rate = lv2host_get_sample_rate;
  497. host->get_time_info = lv2host_get_time_info;
  498. host->write_midi_event = lv2host_write_midi_event;
  499. host->ui_parameter_changed = lv2host_ui_parameter_changed;
  500. host->ui_custom_data_changed = lv2host_ui_custom_data_changed;
  501. host->ui_closed = lv2host_ui_closed;
  502. host->ui_open_file = lv2host_ui_open_file;
  503. host->ui_save_file = lv2host_ui_save_file;
  504. host->dispatcher = lv2host_dispatcher;
  505. return new CarlaEngineNative(host, lv2Host);
  506. }
  507. static void lv2_connect_port(LV2_Handle handle, uint32_t port, void* dataLocation)
  508. {
  509. if (port < 4)
  510. handlePtr->fLv2Host->audioPorts[port] = (float*)dataLocation;
  511. else if (port == 4)
  512. handlePtr->fLv2Host->atomPort = (LV2_Atom_Sequence*)dataLocation;
  513. }
  514. static void lv2_activate(LV2_Handle handle)
  515. {
  516. handlePtr->activate();
  517. }
  518. static void lv2_run(LV2_Handle handle, uint32_t sampleCount)
  519. {
  520. float* inBuffer[2] = { handlePtr->fLv2Host->audioPorts[0], handlePtr->fLv2Host->audioPorts[1] };
  521. float* outBuffer[2] = { handlePtr->fLv2Host->audioPorts[2], handlePtr->fLv2Host->audioPorts[3] };
  522. // TODO - get midiEvents and timePos from atomPort
  523. handlePtr->process(inBuffer, outBuffer, sampleCount, 0, nullptr);
  524. }
  525. static void lv2_deactivate(LV2_Handle handle)
  526. {
  527. handlePtr->deactivate();
  528. }
  529. static void lv2_cleanup(LV2_Handle handle)
  530. {
  531. delete handlePtr;
  532. }
  533. static const void* lv2_extension_data(const char* /*uri*/)
  534. {
  535. return nullptr;
  536. }
  537. #undef handlePtr
  538. #endif
  539. private:
  540. PluginDescriptorClassEND(CarlaEngineNative)
  541. CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineNative)
  542. };
  543. // -----------------------------------------------------------------------
  544. static const PluginDescriptor carlaDesc = {
  545. /* category */ ::PLUGIN_CATEGORY_OTHER,
  546. /* hints */ static_cast< ::PluginHints>(::PLUGIN_IS_SYNTH|::PLUGIN_USES_SINGLE_THREAD|::PLUGIN_USES_STATE),
  547. /* audioIns */ 2,
  548. /* audioOuts */ 2,
  549. /* midiIns */ 1,
  550. /* midiOuts */ 1,
  551. /* paramIns */ 0,
  552. /* paramOuts */ 0,
  553. /* name */ "Carla-Plugin",
  554. /* label */ "carla",
  555. /* maker */ "falkTX",
  556. /* copyright */ "GNU GPL v2+",
  557. PluginDescriptorFILL(CarlaEngineNative)
  558. };
  559. #ifdef WANT_LV2
  560. static const LV2_Descriptor carlaLv2Desc = {
  561. /* URI */ "http://kxstudio.sf.net/carla",
  562. /* instantiate */ CarlaEngineNative::lv2_instantiate,
  563. /* connect_port */ CarlaEngineNative::lv2_connect_port,
  564. /* activate */ CarlaEngineNative::lv2_activate,
  565. /* run */ CarlaEngineNative::lv2_run,
  566. /* deactivate */ CarlaEngineNative::lv2_deactivate,
  567. /* cleanup */ CarlaEngineNative::lv2_cleanup,
  568. /* extension_data */ CarlaEngineNative::lv2_extension_data
  569. };
  570. #endif
  571. void CarlaEngine::registerNativePlugin()
  572. {
  573. carla_register_native_plugin(&carlaDesc);
  574. }
  575. CARLA_BACKEND_END_NAMESPACE
  576. // -----------------------------------------------------------------------
  577. #ifdef WANT_LV2
  578. CARLA_EXPORT
  579. const LV2_Descriptor* lv2_descriptor(uint32_t index)
  580. {
  581. CARLA_BACKEND_USE_NAMESPACE;
  582. return (index == 0) ? &carlaLv2Desc : nullptr;
  583. }
  584. #endif
  585. // -----------------------------------------------------------------------
  586. #endif // ! BUILD_BRIDGE