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.

767 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. #define WANT_LV2
  19. #include "CarlaEngineInternal.hpp"
  20. #include "CarlaStateUtils.hpp"
  21. #include "CarlaNative.hpp"
  22. #ifdef WANT_LV2
  23. # include "lv2/lv2.h"
  24. # include "lv2/atom.h"
  25. struct Lv2HostDescriptor {
  26. uint32_t bufferSize;
  27. double sampleRate;
  28. TimeInfo timeInfo;
  29. float* audioPorts[4];
  30. LV2_Atom_Sequence* atomPort;
  31. Lv2HostDescriptor()
  32. : bufferSize(0),
  33. sampleRate(0.0),
  34. audioPorts{nullptr},
  35. atomPort(nullptr) {}
  36. };
  37. #else
  38. struct Lv2HostDescriptor;
  39. #endif
  40. #include <QtCore/QTextStream>
  41. CARLA_BACKEND_START_NAMESPACE
  42. // -----------------------------------------------------------------------
  43. class CarlaEngineNative : public PluginDescriptorClass,
  44. public CarlaEngine
  45. {
  46. public:
  47. CarlaEngineNative(const HostDescriptor* const host, Lv2HostDescriptor* const lv2Host = nullptr)
  48. : PluginDescriptorClass(host),
  49. CarlaEngine(),
  50. fLv2Host(lv2Host)
  51. {
  52. carla_debug("CarlaEngineNative::CarlaEngineNative()");
  53. // set-up engine
  54. fOptions.processMode = PROCESS_MODE_CONTINUOUS_RACK;
  55. fOptions.transportMode = TRANSPORT_MODE_PLUGIN;
  56. fOptions.forceStereo = true;
  57. fOptions.preferPluginBridges = false;
  58. fOptions.preferUiBridges = false;
  59. init("Carla-Plugin");
  60. }
  61. ~CarlaEngineNative() override
  62. {
  63. carla_debug("CarlaEngineNative::~CarlaEngineNative()");
  64. setAboutToClose();
  65. removeAllPlugins();
  66. close();
  67. #ifdef WANT_LV2
  68. if (fLv2Host != nullptr)
  69. {
  70. delete fLv2Host;
  71. delete hostHandle();
  72. }
  73. #endif
  74. }
  75. protected:
  76. // -------------------------------------
  77. // CarlaEngine virtual calls
  78. bool init(const char* const clientName) override
  79. {
  80. carla_debug("CarlaEngineNative::init(\"%s\")", clientName);
  81. fBufferSize = PluginDescriptorClass::getBufferSize();
  82. fSampleRate = PluginDescriptorClass::getSampleRate();
  83. CarlaEngine::init(clientName);
  84. return true;
  85. }
  86. bool close() override
  87. {
  88. carla_debug("CarlaEngineNative::close()");
  89. proccessPendingEvents();
  90. return CarlaEngine::close();
  91. }
  92. bool isRunning() const override
  93. {
  94. return true;
  95. }
  96. bool isOffline() const override
  97. {
  98. return false;
  99. }
  100. EngineType type() const override
  101. {
  102. return kEngineTypePlugin;
  103. }
  104. // -------------------------------------------------------------------
  105. // Plugin parameter calls
  106. uint32_t getParameterCount() override
  107. {
  108. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  109. return 0;
  110. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  111. if (plugin == nullptr || ! plugin->enabled())
  112. return 0;
  113. return kData->plugins[0].plugin->parameterCount();
  114. }
  115. const Parameter* getParameterInfo(const uint32_t index) override
  116. {
  117. if (index >= getParameterCount())
  118. return nullptr;
  119. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  120. if (plugin == nullptr || ! plugin->enabled())
  121. return nullptr;
  122. static ::Parameter param;
  123. static char strBufName[STR_MAX+1];
  124. static char strBufUnit[STR_MAX+1];
  125. const ParameterData& paramData(plugin->parameterData(index));
  126. const ParameterRanges& paramRanges(plugin->parameterRanges(index));
  127. plugin->getParameterName(index, strBufName);
  128. plugin->getParameterUnit(index, strBufUnit);
  129. unsigned int hints = 0x0;
  130. if (paramData.hints & PARAMETER_IS_BOOLEAN)
  131. hints |= ::PARAMETER_IS_BOOLEAN;
  132. if (paramData.hints & PARAMETER_IS_INTEGER)
  133. hints |= ::PARAMETER_IS_INTEGER;
  134. if (paramData.hints & PARAMETER_IS_LOGARITHMIC)
  135. hints |= ::PARAMETER_IS_LOGARITHMIC;
  136. if (paramData.hints & PARAMETER_IS_AUTOMABLE)
  137. hints |= ::PARAMETER_IS_AUTOMABLE;
  138. if (paramData.hints & PARAMETER_USES_SAMPLERATE)
  139. hints |= ::PARAMETER_USES_SAMPLE_RATE;
  140. if (paramData.hints & PARAMETER_USES_SCALEPOINTS)
  141. hints |= ::PARAMETER_USES_SCALEPOINTS;
  142. if (paramData.hints & PARAMETER_USES_CUSTOM_TEXT)
  143. hints |= ::PARAMETER_USES_CUSTOM_TEXT;
  144. if (paramData.type == PARAMETER_INPUT || paramData.type == PARAMETER_OUTPUT)
  145. {
  146. if (paramData.hints & PARAMETER_IS_ENABLED)
  147. hints |= ::PARAMETER_IS_ENABLED;
  148. if (paramData.type == PARAMETER_OUTPUT)
  149. hints |= ::PARAMETER_IS_OUTPUT;
  150. }
  151. param.hints = static_cast< ::ParameterHints>(hints);
  152. param.name = strBufName;
  153. param.unit = strBufUnit;
  154. param.ranges.def = paramRanges.def;
  155. param.ranges.min = paramRanges.min;
  156. param.ranges.max = paramRanges.max;
  157. param.ranges.step = paramRanges.step;
  158. param.ranges.stepSmall = paramRanges.stepSmall;
  159. param.ranges.stepLarge = paramRanges.stepLarge;
  160. param.scalePointCount = 0; // TODO
  161. param.scalePoints = nullptr;
  162. return &param;
  163. }
  164. float getParameterValue(const uint32_t index) override
  165. {
  166. if (index >= getParameterCount())
  167. return 0.0f;
  168. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  169. if (plugin == nullptr || ! plugin->enabled())
  170. return 0.0f;
  171. return plugin->getParameterValue(index);
  172. }
  173. const char* getParameterText(const uint32_t index) override
  174. {
  175. if (index >= getParameterCount())
  176. return nullptr;
  177. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  178. if (plugin == nullptr || ! plugin->enabled())
  179. return nullptr;
  180. static char strBuf[STR_MAX+1];
  181. plugin->getParameterText(index, strBuf);
  182. return strBuf;
  183. }
  184. // -------------------------------------------------------------------
  185. // Plugin midi-program calls
  186. uint32_t getMidiProgramCount() override
  187. {
  188. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  189. return 0;
  190. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  191. if (plugin == nullptr || ! plugin->enabled())
  192. return 0.0f;
  193. return plugin->midiProgramCount();
  194. }
  195. const MidiProgram* getMidiProgramInfo(const uint32_t index) override
  196. {
  197. if (index >= getMidiProgramCount())
  198. return nullptr;
  199. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  200. if (plugin == nullptr || ! plugin->enabled())
  201. return nullptr;
  202. static ::MidiProgram midiProg;
  203. {
  204. const MidiProgramData& midiProgData(plugin->midiProgramData(index));
  205. midiProg.bank = midiProgData.bank;
  206. midiProg.program = midiProgData.program;
  207. midiProg.name = midiProgData.name;
  208. }
  209. return &midiProg;
  210. }
  211. // -------------------------------------------------------------------
  212. // Plugin state calls
  213. void setParameterValue(const uint32_t index, const float value) override
  214. {
  215. if (index >= getParameterCount())
  216. return;
  217. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  218. if (plugin == nullptr || ! plugin->enabled())
  219. return;
  220. plugin->setParameterValue(index, value, false, false, false);
  221. }
  222. void setMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  223. {
  224. if (kData->curPluginCount == 0 || kData->plugins == nullptr)
  225. return;
  226. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  227. if (plugin == nullptr || ! plugin->enabled())
  228. return;
  229. plugin->setMidiProgramById(bank, program, false, false, false);
  230. }
  231. void setCustomData(const char* const key, const char* const value) override
  232. {
  233. CARLA_ASSERT(key != nullptr);
  234. CARLA_ASSERT(value != nullptr);
  235. return;
  236. // TODO
  237. // unused
  238. (void)key;
  239. (void)value;
  240. }
  241. // -------------------------------------------------------------------
  242. // Plugin process calls
  243. void activate() override
  244. {
  245. for (uint32_t i=0; i < kData->curPluginCount; ++i)
  246. {
  247. CarlaPlugin* const plugin(kData->plugins[i].plugin);
  248. if (plugin == nullptr || ! plugin->enabled())
  249. continue;
  250. plugin->setActive(true, true, false);
  251. }
  252. }
  253. void deactivate() override
  254. {
  255. for (uint32_t i=0; i < kData->curPluginCount; ++i)
  256. {
  257. CarlaPlugin* const plugin(kData->plugins[i].plugin);
  258. if (plugin == nullptr || ! plugin->enabled())
  259. continue;
  260. plugin->setActive(false, true, false);
  261. }
  262. // just in case
  263. proccessPendingEvents();
  264. }
  265. void process(float** const inBuffer, float** const outBuffer, const uint32_t frames, const uint32_t midiEventCount, const ::MidiEvent* const midiEvents) override
  266. {
  267. if (kData->curPluginCount == 0)
  268. {
  269. carla_zeroFloat(outBuffer[0], frames);
  270. carla_zeroFloat(outBuffer[1], frames);
  271. return CarlaEngine::proccessPendingEvents();
  272. }
  273. // ---------------------------------------------------------------
  274. // Time Info
  275. const ::TimeInfo* timeInfo(PluginDescriptorClass::getTimeInfo());
  276. fTimeInfo.playing = timeInfo->playing;
  277. fTimeInfo.frame = timeInfo->frame;
  278. fTimeInfo.usecs = timeInfo->usecs;
  279. fTimeInfo.valid = 0x0;
  280. if (timeInfo->bbt.valid)
  281. {
  282. fTimeInfo.valid |= EngineTimeInfo::ValidBBT;
  283. fTimeInfo.bbt.bar = timeInfo->bbt.bar;
  284. fTimeInfo.bbt.beat = timeInfo->bbt.beat;
  285. fTimeInfo.bbt.tick = timeInfo->bbt.tick;
  286. fTimeInfo.bbt.barStartTick = timeInfo->bbt.barStartTick;
  287. fTimeInfo.bbt.beatsPerBar = timeInfo->bbt.beatsPerBar;
  288. fTimeInfo.bbt.beatType = timeInfo->bbt.beatType;
  289. fTimeInfo.bbt.ticksPerBeat = timeInfo->bbt.ticksPerBeat;
  290. fTimeInfo.bbt.beatsPerMinute = timeInfo->bbt.beatsPerMinute;
  291. }
  292. // ---------------------------------------------------------------
  293. // initialize input events
  294. carla_zeroStruct<EngineEvent>(kData->rack.in, RACK_EVENT_COUNT);
  295. {
  296. uint32_t engineEventIndex = 0;
  297. for (uint32_t i=0; i < midiEventCount && engineEventIndex < RACK_EVENT_COUNT; ++i)
  298. {
  299. const ::MidiEvent& midiEvent(midiEvents[i]);
  300. if (midiEvent.size > 4)
  301. continue;
  302. const uint8_t status = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  303. const uint8_t channel = MIDI_GET_CHANNEL_FROM_DATA(midiEvent.data);
  304. // we don't want some events
  305. if (status == MIDI_STATUS_PROGRAM_CHANGE)
  306. continue;
  307. // handle note/sound off properly
  308. if (status == MIDI_STATUS_CONTROL_CHANGE)
  309. {
  310. const uint8_t control = midiEvent.data[1];
  311. if (MIDI_IS_CONTROL_BANK_SELECT(control))
  312. continue;
  313. if (control == MIDI_CONTROL_ALL_SOUND_OFF || control == MIDI_CONTROL_ALL_NOTES_OFF)
  314. {
  315. EngineEvent& engineEvent(kData->rack.in[engineEventIndex++]);
  316. engineEvent.clear();
  317. engineEvent.type = kEngineEventTypeControl;
  318. engineEvent.time = midiEvent.time;
  319. engineEvent.channel = channel;
  320. engineEvent.ctrl.type = (control == MIDI_CONTROL_ALL_SOUND_OFF) ? kEngineControlEventTypeAllSoundOff : kEngineControlEventTypeAllNotesOff;
  321. engineEvent.ctrl.param = 0;
  322. engineEvent.ctrl.value = 0.0f;
  323. continue;
  324. }
  325. }
  326. EngineEvent& engineEvent(kData->rack.in[engineEventIndex++]);
  327. engineEvent.clear();
  328. engineEvent.type = kEngineEventTypeMidi;
  329. engineEvent.time = midiEvent.time;
  330. engineEvent.channel = channel;
  331. engineEvent.midi.data[0] = MIDI_GET_STATUS_FROM_DATA(midiEvent.data);
  332. engineEvent.midi.data[1] = midiEvent.data[1];
  333. engineEvent.midi.data[2] = midiEvent.data[2];
  334. engineEvent.midi.data[3] = midiEvent.data[3];
  335. engineEvent.midi.size = midiEvent.size;
  336. }
  337. }
  338. // ---------------------------------------------------------------
  339. // create audio buffers
  340. float* inBuf[2] = { inBuffer[0], inBuffer[1] };
  341. float* outBuf[2] = { outBuffer[0], outBuffer[1] };
  342. // ---------------------------------------------------------------
  343. // process
  344. CarlaEngine::processRack(inBuf, outBuf, frames);
  345. CarlaEngine::proccessPendingEvents();
  346. }
  347. // -------------------------------------------------------------------
  348. // Plugin UI calls
  349. void uiShow(const bool show) override
  350. {
  351. return;
  352. // TODO
  353. // unused
  354. (void)show;
  355. }
  356. void uiIdle() override
  357. {
  358. CarlaEngine::idle();
  359. }
  360. void uiSetParameterValue(const uint32_t index, const float value) override
  361. {
  362. if (index >= getParameterCount())
  363. return;
  364. CarlaPlugin* const plugin(kData->plugins[0].plugin);
  365. if (plugin == nullptr || ! plugin->enabled())
  366. return;
  367. plugin->uiParameterChange(index, value);
  368. }
  369. void uiSetMidiProgram(const uint8_t channel, const uint32_t bank, const uint32_t program) override
  370. {
  371. return;
  372. // TODO
  373. // unused
  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