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.

887 lines
22KB

  1. /*
  2. * Carla Plugin bridge code
  3. * Copyright (C) 2012 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. #ifdef BUILD_BRIDGE_PLUGIN
  18. #include "carla_bridge_client.hpp"
  19. #include "carla_backend_utils.hpp"
  20. #include "carla_plugin.hpp"
  21. #include <set>
  22. #include <QtCore/QDir>
  23. #include <QtCore/QFile>
  24. #include <QtCore/QTextStream>
  25. #include <QtCore/QTimerEvent>
  26. #include <QtGui/QApplication>
  27. #include <QtGui/QMainWindow>
  28. #include <QtGui/QtEvents>
  29. #ifdef Q_OS_UNIX
  30. # include <signal.h>
  31. #endif
  32. static int qargc = 0;
  33. static char** qargv = nullptr;
  34. static bool qCloseNow = false;
  35. static bool qSaveNow = false;
  36. #if defined(Q_OS_HAIKU) || defined(Q_OS_UNIX)
  37. void closeSignalHandler(int)
  38. {
  39. qCloseNow = true;
  40. }
  41. void saveSignalHandler(int)
  42. {
  43. qSaveNow = true;
  44. }
  45. #elif defined(Q_OS_WIN)
  46. BOOL WINAPI closeSignalHandler(DWORD dwCtrlType)
  47. {
  48. if (dwCtrlType == CTRL_C_EVENT)
  49. {
  50. qCloseNow = true;
  51. return TRUE;
  52. }
  53. return FALSE;
  54. }
  55. #endif
  56. void initSignalHandler()
  57. {
  58. #if defined(Q_OS_HAIKU) || defined(Q_OS_UNIX)
  59. struct sigaction sint;
  60. struct sigaction sterm;
  61. struct sigaction susr1;
  62. sint.sa_handler = closeSignalHandler;
  63. sint.sa_flags = SA_RESTART;
  64. sint.sa_restorer = nullptr;
  65. sigemptyset(&sint.sa_mask);
  66. sigaction(SIGINT, &sint, nullptr);
  67. sterm.sa_handler = closeSignalHandler;
  68. sterm.sa_flags = SA_RESTART;
  69. sterm.sa_restorer = nullptr;
  70. sigemptyset(&sterm.sa_mask);
  71. sigaction(SIGTERM, &sterm, nullptr);
  72. susr1.sa_handler = saveSignalHandler;
  73. susr1.sa_flags = SA_RESTART;
  74. susr1.sa_restorer = nullptr;
  75. sigemptyset(&susr1.sa_mask);
  76. sigaction(SIGUSR1, &susr1, nullptr);
  77. #elif defined(Q_OS_WIN)
  78. SetConsoleCtrlHandler(closeSignalHandler, TRUE);
  79. #endif
  80. }
  81. CARLA_BRIDGE_START_NAMESPACE
  82. // -------------------------------------------------------------------------
  83. class BridgePluginGUI : public QMainWindow
  84. {
  85. public:
  86. class Callback
  87. {
  88. public:
  89. virtual ~Callback() {}
  90. virtual void guiClosedCallback() = 0;
  91. };
  92. BridgePluginGUI(QWidget* const parent, Callback* const callback_)
  93. : QMainWindow(parent),
  94. callback(callback_)
  95. {
  96. qDebug("BridgePluginGUI::BridgePluginGUI(%p, %p", parent, callback);
  97. CARLA_ASSERT(callback);
  98. m_firstShow = true;
  99. m_resizable = true;
  100. container = new GuiContainer(this);
  101. setCentralWidget(container);
  102. setNewSize(50, 50);
  103. }
  104. ~BridgePluginGUI()
  105. {
  106. qDebug("BridgePluginGUI::~BridgePluginGUI()");
  107. CARLA_ASSERT(container);
  108. delete container;
  109. }
  110. GuiContainer* getContainer()
  111. {
  112. return container;
  113. }
  114. void setResizable(bool resizable)
  115. {
  116. m_resizable = resizable;
  117. setNewSize(width(), height());
  118. #ifdef Q_OS_WIN
  119. if (! resizable)
  120. setWindowFlags(windowFlags() | Qt::MSWindowsFixedSizeDialogHint);
  121. #endif
  122. }
  123. void setTitle(const char* title)
  124. {
  125. CARLA_ASSERT(title);
  126. setWindowTitle(QString("%1 (GUI)").arg(title));
  127. }
  128. void setNewSize(int width, int height)
  129. {
  130. qDebug("BridgePluginGUI::setNewSize(%i, %i)", width, height);
  131. if (width < 30)
  132. width = 30;
  133. if (height < 30)
  134. height = 30;
  135. if (m_resizable)
  136. {
  137. resize(width, height);
  138. }
  139. else
  140. {
  141. setFixedSize(width, height);
  142. container->setFixedSize(width, height);
  143. }
  144. }
  145. void setVisible(const bool yesNo)
  146. {
  147. qDebug("BridgePluginGUI::setVisible(%s)", bool2str(yesNo));
  148. if (yesNo)
  149. {
  150. if (m_firstShow)
  151. {
  152. m_firstShow = false;
  153. restoreGeometry(QByteArray());
  154. }
  155. else if (! m_geometry.isNull())
  156. restoreGeometry(m_geometry);
  157. }
  158. else
  159. m_geometry = saveGeometry();
  160. QMainWindow::setVisible(yesNo);
  161. }
  162. protected:
  163. void hideEvent(QHideEvent* const event)
  164. {
  165. qDebug("BridgePluginGUI::hideEvent(%p)", event);
  166. event->accept();
  167. close();
  168. }
  169. void closeEvent(QCloseEvent* const event)
  170. {
  171. qDebug("BridgePluginGUI::closeEvent(%p)", event);
  172. if (event->spontaneous())
  173. {
  174. callback->guiClosedCallback();
  175. QMainWindow::closeEvent(event);
  176. return;
  177. }
  178. event->ignore();
  179. }
  180. private:
  181. Callback* const callback;
  182. GuiContainer* container;
  183. bool m_firstShow;
  184. bool m_resizable;
  185. QByteArray m_geometry;
  186. };
  187. // -------------------------------------------------------------------------
  188. class BridgePluginClient : public CarlaToolkit,
  189. public CarlaClient,
  190. public BridgePluginGUI::Callback,
  191. public QApplication
  192. {
  193. public:
  194. BridgePluginClient()
  195. : CarlaToolkit("carla-bridge-plugin"),
  196. CarlaClient(this),
  197. QApplication(qargc, qargv, true)
  198. {
  199. qDebug("BridgePluginClient::BridgePluginClient()");
  200. msgTimerGUI = 0;
  201. msgTimerOSC = 0;
  202. engine = nullptr;
  203. plugin = nullptr;
  204. pluginGui = nullptr;
  205. m_client = this;
  206. m_doQuit = false;
  207. m_hasUI = false;
  208. m_qt4UI = false;
  209. m_needsResize = false;
  210. m_nextSize[0] = 0;
  211. m_nextSize[1] = 0;
  212. }
  213. ~BridgePluginClient()
  214. {
  215. qDebug("BridgePluginClient::~BridgePluginClient()");
  216. CARLA_ASSERT(msgTimerGUI == 0);
  217. CARLA_ASSERT(msgTimerOSC == 0);
  218. CARLA_ASSERT(! pluginGui);
  219. }
  220. void setStuff(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin)
  221. {
  222. qDebug("BridgePluginClient::setStuff(%p, %p)", engine, plugin);
  223. CARLA_ASSERT(engine);
  224. CARLA_ASSERT(plugin);
  225. this->engine = engine;
  226. this->plugin = plugin;
  227. }
  228. // ---------------------------------------------------------------------
  229. // toolkit
  230. void init()
  231. {
  232. qDebug("BridgePluginClient::init()");
  233. pluginGui = new BridgePluginGUI(nullptr, this);
  234. pluginGui->hide();
  235. }
  236. void exec(CarlaClient* const, const bool showGui)
  237. {
  238. qDebug("BridgePluginClient::exec()");
  239. if (showGui)
  240. {
  241. if (m_hasUI)
  242. show();
  243. m_doQuit = true;
  244. }
  245. else
  246. {
  247. CarlaClient::sendOscUpdate();
  248. CarlaClient::sendOscBridgeUpdate();
  249. QApplication::setQuitOnLastWindowClosed(false);
  250. }
  251. msgTimerGUI = startTimer(50);
  252. msgTimerOSC = startTimer(25);
  253. QApplication::exec();
  254. }
  255. void quit()
  256. {
  257. qDebug("BridgePluginClient::quit()");
  258. if (msgTimerGUI != 0)
  259. {
  260. QApplication::killTimer(msgTimerGUI);
  261. msgTimerGUI = 0;
  262. }
  263. if (msgTimerOSC != 0)
  264. {
  265. QApplication::killTimer(msgTimerOSC);
  266. msgTimerOSC = 0;
  267. }
  268. if (pluginGui)
  269. {
  270. if (pluginGui->isVisible())
  271. hide();
  272. pluginGui->close();
  273. delete pluginGui;
  274. pluginGui = nullptr;
  275. }
  276. if (! QApplication::closingDown())
  277. QApplication::quit();
  278. }
  279. void show()
  280. {
  281. qDebug("BridgePluginClient::show()");
  282. CARLA_ASSERT(pluginGui);
  283. if (plugin)
  284. plugin->showGui(true);
  285. if (pluginGui && m_qt4UI)
  286. pluginGui->show();
  287. }
  288. void hide()
  289. {
  290. qDebug("BridgePluginClient::hide()");
  291. CARLA_ASSERT(pluginGui);
  292. if (pluginGui && m_qt4UI)
  293. pluginGui->hide();
  294. if (plugin)
  295. plugin->showGui(false);
  296. }
  297. void resize(int width, int height)
  298. {
  299. qDebug("BridgePluginClient::resize(%i, %i)", width, height);
  300. CARLA_ASSERT(pluginGui);
  301. if (pluginGui)
  302. pluginGui->setNewSize(width, height);
  303. }
  304. // ---------------------------------------------------------------------
  305. void createWindow(const bool resizable)
  306. {
  307. qDebug("BridgePluginClient::createWindow(%s)", bool2str(resizable));
  308. CARLA_ASSERT(plugin);
  309. CARLA_ASSERT(pluginGui);
  310. if (! (plugin && pluginGui))
  311. return;
  312. m_hasUI = true;
  313. m_qt4UI = true;
  314. pluginGui->setResizable(resizable);
  315. pluginGui->setTitle(plugin->name());
  316. plugin->setGuiContainer(pluginGui->getContainer());
  317. }
  318. void enableUI()
  319. {
  320. m_hasUI = true;
  321. }
  322. // ---------------------------------------------------------------------
  323. // processing
  324. void setParameter(const int32_t rindex, const double value)
  325. {
  326. qDebug("CarlaPluginClient::setParameter(%i, %g)", rindex, value);
  327. CARLA_ASSERT(plugin);
  328. if (! plugin)
  329. return;
  330. plugin->setParameterValueByRIndex(rindex, value, true, true, false);
  331. }
  332. void setProgram(const uint32_t index)
  333. {
  334. qDebug("CarlaPluginClient::setProgram(%i)", index);
  335. CARLA_ASSERT(engine);
  336. CARLA_ASSERT(plugin);
  337. CARLA_ASSERT(index < plugin->programCount());
  338. if (! (plugin && engine))
  339. return;
  340. if (index >= plugin->programCount())
  341. return;
  342. plugin->setProgram(index, true, true, false, true);
  343. double value;
  344. for (uint32_t i=0; i < plugin->parameterCount(); i++)
  345. {
  346. value = plugin->getParameterValue(i);
  347. engine->osc_send_bridge_set_parameter_value(i, value);
  348. engine->osc_send_bridge_set_default_value(i, value);
  349. }
  350. }
  351. void setMidiProgram(const uint32_t index)
  352. {
  353. qDebug("CarlaPluginClient::setMidiProgram(%i)", index);
  354. CARLA_ASSERT(engine);
  355. CARLA_ASSERT(plugin);
  356. if (! (plugin && engine))
  357. return;
  358. plugin->setMidiProgram(index, true, true, false, true);
  359. double value;
  360. for (uint32_t i=0; i < plugin->parameterCount(); i++)
  361. {
  362. value = plugin->getParameterValue(i);
  363. engine->osc_send_bridge_set_parameter_value(i, value);
  364. engine->osc_send_bridge_set_default_value(i, value);
  365. }
  366. }
  367. void noteOn(const uint8_t channel, const uint8_t note, const uint8_t velo)
  368. {
  369. qDebug("CarlaPluginClient::noteOn(%i, %i, %i)", channel, note, velo);
  370. CARLA_ASSERT(plugin);
  371. CARLA_ASSERT(velo > 0);
  372. if (! plugin)
  373. return;
  374. plugin->sendMidiSingleNote(channel, note, velo, true, true, false);
  375. }
  376. void noteOff(const uint8_t channel, const uint8_t note)
  377. {
  378. qDebug("CarlaPluginClient::noteOff(%i, %i)", channel, note);
  379. CARLA_ASSERT(plugin);
  380. if (! plugin)
  381. return;
  382. plugin->sendMidiSingleNote(channel, note, 0, true, true, false);
  383. }
  384. // ---------------------------------------------------------------------
  385. // plugin
  386. void saveNow()
  387. {
  388. qDebug("CarlaPluginClient::saveNow()");
  389. CARLA_ASSERT(plugin);
  390. CARLA_ASSERT(engine);
  391. if (! (plugin && engine))
  392. return;
  393. plugin->prepareForSave();
  394. for (uint32_t i=0; i < plugin->customDataCount(); i++)
  395. {
  396. const CarlaBackend::CustomData* const cdata = plugin->customData(i);
  397. engine->osc_send_bridge_set_custom_data(cdata->type, cdata->key, cdata->value);
  398. }
  399. if (plugin->hints() & CarlaBackend::PLUGIN_USES_CHUNKS)
  400. {
  401. void* data = nullptr;
  402. int32_t dataSize = plugin->chunkData(&data);
  403. if (data && dataSize >= 4)
  404. {
  405. QString filePath;
  406. filePath = QDir::tempPath();
  407. #ifdef Q_OS_WIN
  408. filePath += "\\.CarlaChunk_";
  409. #else
  410. filePath += "/.CarlaChunk_";
  411. #endif
  412. filePath += plugin->name();
  413. QFile file(filePath);
  414. if (file.open(QIODevice::WriteOnly))
  415. {
  416. QByteArray chunk((const char*)data, dataSize);
  417. file.write(chunk);
  418. file.close();
  419. engine->osc_send_bridge_set_chunk_data(filePath.toUtf8().constData());
  420. }
  421. }
  422. }
  423. engine->osc_send_bridge_configure(CarlaBackend::CARLA_BRIDGE_MSG_SAVED, "");
  424. }
  425. void setCustomData(const char* const type, const char* const key, const char* const value)
  426. {
  427. qDebug("CarlaPluginClient::setCustomData(\"%s\", \"%s\", \"%s\")", type, key, value);
  428. CARLA_ASSERT(plugin);
  429. if (! plugin)
  430. return;
  431. plugin->setCustomData(type, key, value, true);
  432. }
  433. void setChunkData(const char* const filePath)
  434. {
  435. qDebug("CarlaPluginClient::setChunkData(\"%s\")", filePath);
  436. CARLA_ASSERT(plugin);
  437. if (! plugin)
  438. return;
  439. QString chunkFilePath(filePath);
  440. #ifdef Q_OS_WIN
  441. if (chunkFilePath.startsWith("/"))
  442. {
  443. // running under Wine, posix host
  444. chunkFilePath = chunkFilePath.replace(0, 1, "Z:/");
  445. chunkFilePath = QDir::toNativeSeparators(chunkFilePath);
  446. }
  447. #endif
  448. QFile chunkFile(chunkFilePath);
  449. if (plugin && chunkFile.open(QIODevice::ReadOnly | QIODevice::Text))
  450. {
  451. QTextStream in(&chunkFile);
  452. QString stringData(in.readAll());
  453. chunkFile.close();
  454. chunkFile.remove();
  455. plugin->setChunkData(stringData.toUtf8().constData());
  456. }
  457. }
  458. // ---------------------------------------------------------------------
  459. // callback
  460. void handleCallback(const CarlaBackend::CallbackType action, const int value1, const int value2, const double value3, const char* const valueStr)
  461. {
  462. qDebug("CarlaPluginClient::handleCallback(%s, %i, %i, %g \"%s\")", CarlaBackend::CallbackType2Str(action), value1, value2, value3, valueStr);
  463. if (! engine)
  464. return;
  465. switch (action)
  466. {
  467. case CarlaBackend::CALLBACK_PARAMETER_VALUE_CHANGED:
  468. #if 0
  469. parametersToUpdate.insert(value1);
  470. #endif
  471. engine->osc_send_bridge_set_parameter_value(value1, value3);
  472. break;
  473. case CarlaBackend::CALLBACK_PROGRAM_CHANGED:
  474. engine->osc_send_bridge_set_program(value1);
  475. break;
  476. case CarlaBackend::CALLBACK_MIDI_PROGRAM_CHANGED:
  477. engine->osc_send_bridge_set_midi_program(value1);
  478. break;
  479. case CarlaBackend::CALLBACK_NOTE_ON:
  480. {
  481. //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_ON, (uint8_t)value1, (uint8_t)value2 };
  482. //osc_send_midi(mdata);
  483. break;
  484. }
  485. case CarlaBackend::CALLBACK_NOTE_OFF:
  486. {
  487. //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_OFF, (uint8_t)value1, (uint8_t)value2 };
  488. //osc_send_midi(mdata);
  489. break;
  490. }
  491. case CarlaBackend::CALLBACK_SHOW_GUI:
  492. if (value1 == 0)
  493. {
  494. engine->osc_send_bridge_configure(CarlaBackend::CARLA_BRIDGE_MSG_HIDE_GUI, "");
  495. if (m_doQuit)
  496. qCloseNow = true;
  497. }
  498. break;
  499. case CarlaBackend::CALLBACK_RESIZE_GUI:
  500. CARLA_ASSERT(value1 > 0 && value2 > 0);
  501. CARLA_ASSERT(pluginGui);
  502. if (value1 > 0 && value2 > 0 && pluginGui)
  503. {
  504. m_needsResize = true;
  505. m_nextSize[0] = value1;
  506. m_nextSize[1] = value2;
  507. }
  508. break;
  509. case CarlaBackend::CALLBACK_RELOAD_PARAMETERS:
  510. //if (CARLA_PLUGIN)
  511. //{
  512. // for (uint32_t i=0; i < CARLA_PLUGIN->parameterCount(); i++)
  513. // {
  514. // osc_send_control(i, CARLA_PLUGIN->getParameterValue(i));
  515. // }
  516. //}
  517. break;
  518. case CarlaBackend::CALLBACK_QUIT:
  519. //QApplication::quit();
  520. break;
  521. default:
  522. break;
  523. }
  524. }
  525. // ---------------------------------------------------------------------
  526. static void callback(void* const ptr, CarlaBackend::CallbackType const action, const unsigned short, const int value1, const int value2, const double value3, const char* const valueStr)
  527. {
  528. CARLA_ASSERT(ptr);
  529. if (! ptr)
  530. return;
  531. BridgePluginClient* const _this_ = (BridgePluginClient*)ptr;
  532. _this_->handleCallback(action, value1, value2, value3, valueStr);
  533. }
  534. protected:
  535. void guiClosedCallback()
  536. {
  537. if (engine)
  538. engine->osc_send_bridge_configure(CarlaBackend::CARLA_BRIDGE_MSG_HIDE_GUI, "");
  539. }
  540. void timerEvent(QTimerEvent* const event)
  541. {
  542. if (qCloseNow)
  543. return quit();
  544. if (qSaveNow)
  545. {
  546. // TODO
  547. qSaveNow = false;
  548. }
  549. if (event->timerId() == msgTimerGUI)
  550. {
  551. #if 0
  552. if (parametersToUpdate.size() > 0)
  553. {
  554. for (auto it = parametersToUpdate.begin(); it != parametersToUpdate.end(); it++)
  555. {
  556. const int32_t paramId(*it);
  557. engine->osc_send_bridge_set_parameter_value(paramId, plugin->getParameterValue(paramId));
  558. }
  559. parametersToUpdate.clear();
  560. }
  561. #endif
  562. if (plugin)
  563. plugin->idleGui();
  564. if (pluginGui && m_needsResize)
  565. {
  566. pluginGui->setNewSize(m_nextSize[0], m_nextSize[1]);
  567. m_needsResize = false;
  568. }
  569. }
  570. else if (event->timerId() == msgTimerOSC)
  571. {
  572. if (! CarlaClient::oscIdle())
  573. {
  574. CARLA_ASSERT(msgTimerOSC == 0);
  575. msgTimerOSC = 0;
  576. return;
  577. }
  578. }
  579. QApplication::timerEvent(event);
  580. }
  581. // ---------------------------------------------------------------------
  582. private:
  583. int msgTimerGUI, msgTimerOSC;
  584. #if 0
  585. std::set<int32_t> parametersToUpdate;
  586. #endif
  587. bool m_doQuit;
  588. bool m_hasUI;
  589. bool m_qt4UI;
  590. bool m_needsResize;
  591. int m_nextSize[2];
  592. CarlaBackend::CarlaEngine* engine;
  593. CarlaBackend::CarlaPlugin* plugin;
  594. BridgePluginGUI* pluginGui;
  595. };
  596. // -------------------------------------------------------------------------
  597. CARLA_BRIDGE_END_NAMESPACE
  598. int main(int argc, char* argv[])
  599. {
  600. if (argc != 6)
  601. {
  602. qWarning("usage: %s <osc-url|\"null\"> <type> <filename> <name|\"(none)\"> <label>", argv[0]);
  603. return 1;
  604. }
  605. qargc = argc;
  606. qargv = argv;
  607. const char* const oscUrl = argv[1];
  608. const char* const stype = argv[2];
  609. const char* const filename = argv[3];
  610. const char* name = argv[4];
  611. const char* const label = argv[5];
  612. const bool useOsc = strcmp(oscUrl, "null");
  613. if (strcmp(name, "(none)") == 0)
  614. name = nullptr;
  615. CarlaBackend::PluginType itype;
  616. if (strcmp(stype, "LADSPA") == 0)
  617. itype = CarlaBackend::PLUGIN_LADSPA;
  618. else if (strcmp(stype, "DSSI") == 0)
  619. itype = CarlaBackend::PLUGIN_DSSI;
  620. else if (strcmp(stype, "LV2") == 0)
  621. itype = CarlaBackend::PLUGIN_LV2;
  622. else if (strcmp(stype, "VST") == 0)
  623. itype = CarlaBackend::PLUGIN_VST;
  624. else
  625. {
  626. itype = CarlaBackend::PLUGIN_NONE;
  627. qWarning("Invalid plugin type '%s'", stype);
  628. return 1;
  629. }
  630. // Init bridge client
  631. CarlaBridge::BridgePluginClient client;
  632. client.init();
  633. // Init OSC
  634. if (useOsc && ! client.oscInit(oscUrl))
  635. {
  636. client.quit();
  637. return -1;
  638. }
  639. // Listen for ctrl+c or sigint/sigterm events
  640. initSignalHandler();
  641. // Init backend engine
  642. CarlaBackend::CarlaEngine* engine = CarlaBackend::CarlaEngine::newDriverByName("JACK");
  643. engine->setCallback(client.callback, &client);
  644. // bridge client <-> engine
  645. client.registerOscEngine(engine);
  646. // Init engine
  647. QString engName = QString("%1 (master)").arg(name ? name : label);
  648. engName.truncate(engine->maxClientNameSize());
  649. if (! engine->init(engName.toUtf8().constData()))
  650. {
  651. const char* const lastError = engine->getLastError();
  652. qWarning("Bridge engine failed to start, error was:\n%s", lastError);
  653. engine->close();
  654. delete engine;
  655. client.sendOscBridgeError(lastError);
  656. client.quit();
  657. return 2;
  658. }
  659. void* extraStuff = nullptr;
  660. #if 1 // TESTING
  661. static const char* const dssiGUI = "/usr/lib/dssi/calf/calf_gtk";
  662. extraStuff = (void*)dssiGUI;
  663. #endif
  664. // Init plugin
  665. short id = engine->addPlugin(itype, filename, name, label, extraStuff);
  666. int ret;
  667. if (id >= 0 && id < CarlaBackend::MAX_PLUGINS)
  668. {
  669. CarlaBackend::CarlaPlugin* const plugin = engine->getPlugin(id);
  670. client.setStuff(engine, plugin);
  671. // create window if needed
  672. bool guiResizable;
  673. CarlaBackend::GuiType guiType;
  674. plugin->getGuiInfo(&guiType, &guiResizable);
  675. if (guiType == CarlaBackend::GUI_INTERNAL_QT4 || guiType == CarlaBackend::GUI_INTERNAL_COCOA || guiType == CarlaBackend::GUI_INTERNAL_HWND || guiType == CarlaBackend::GUI_INTERNAL_X11)
  676. client.createWindow(guiResizable);
  677. else if (guiType == CarlaBackend::GUI_EXTERNAL_LV2 || guiType == CarlaBackend::GUI_EXTERNAL_OSC)
  678. client.enableUI();
  679. if (! useOsc)
  680. plugin->setActive(true, false, false);
  681. client.exec(nullptr, !useOsc);
  682. ret = 0;
  683. }
  684. else
  685. {
  686. const char* const lastError = engine->getLastError();
  687. qWarning("Plugin failed to load, error was:\n%s", lastError);
  688. if (useOsc)
  689. client.sendOscBridgeError(lastError);
  690. ret = 1;
  691. }
  692. engine->removeAllPlugins();
  693. engine->close();
  694. delete engine;
  695. if (useOsc)
  696. {
  697. // Close OSC
  698. client.oscClose();
  699. // bridge client can't be closed manually, only by host
  700. }
  701. else
  702. {
  703. // Close bridge client
  704. client.quit();
  705. }
  706. return ret;
  707. }
  708. #endif // BUILD_BRIDGE_PLUGIN