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.

866 lines
21KB

  1. /*
  2. * Carla Plugin bridge code
  3. * Copyright (C) 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_bridge_client.h"
  18. #include "carla_plugin.h"
  19. //#include "carla_plugin.h"
  20. #include <QtCore/QFile>
  21. //#ifndef __WINE__
  22. //#include <QtCore/QTimer>
  23. //#include <QtGui/QApplication>
  24. //#include <QtGui/QDialog>
  25. //#endif
  26. CARLA_BRIDGE_START_NAMESPACE
  27. // -------------------------------------------------------------------------
  28. // client
  29. class CarlaBridgePluginClient : public CarlaClient
  30. {
  31. public:
  32. CarlaBridgePluginClient(CarlaToolkit* const toolkit)
  33. : CarlaClient(toolkit)
  34. {
  35. engine = nullptr;
  36. plugin = nullptr;
  37. }
  38. ~CarlaBridgePluginClient()
  39. {
  40. }
  41. void setStuff(CarlaBackend::CarlaEngine* const engine_, CarlaBackend::CarlaPlugin* const plugin_)
  42. {
  43. engine = engine_;
  44. plugin = plugin_;
  45. }
  46. // ---------------------------------------------------------------------
  47. // processing
  48. void setParameter(const int32_t rindex, const double value)
  49. {
  50. Q_ASSERT(plugin);
  51. if (! plugin)
  52. return;
  53. plugin->setParameterValueByRIndex(rindex, value, true, true, false);
  54. }
  55. void setProgram(const uint32_t index)
  56. {
  57. Q_ASSERT(plugin && index < plugin->programCount());
  58. if (! plugin)
  59. return;
  60. if (index >= plugin->programCount())
  61. return;
  62. plugin->setProgram(index, true, true, false, true);
  63. }
  64. void setMidiProgram(const uint32_t bank, const uint32_t program)
  65. {
  66. Q_ASSERT(plugin);
  67. if (! plugin)
  68. return;
  69. plugin->setMidiProgramById(bank, program, true, true, false, true);
  70. }
  71. void noteOn(const uint8_t channel, const uint8_t note, const uint8_t velo)
  72. {
  73. Q_ASSERT(plugin);
  74. Q_ASSERT(velo != 0);
  75. if (! plugin)
  76. return;
  77. plugin->sendMidiSingleNote(channel, note, velo, true, true, false);
  78. }
  79. void noteOff(const uint8_t channel, const uint8_t note)
  80. {
  81. Q_ASSERT(plugin);
  82. if (! plugin)
  83. return;
  84. plugin->sendMidiSingleNote(channel, note, 0, true, true, false);
  85. }
  86. // ---------------------------------------------------------------------
  87. // plugin
  88. void saveNow()
  89. {
  90. Q_ASSERT(plugin);
  91. if (! plugin)
  92. return;
  93. plugin->prepareForSave();
  94. #if 0
  95. for (uint32_t i=0; i < CARLA_PLUGIN->customDataCount(); i++)
  96. {
  97. const CustomData* const cdata = CARLA_PLUGIN->customData(i);
  98. osc_send_bridge_custom_data(customdatatype2str(cdata->type), cdata->key, cdata->value);
  99. }
  100. if (CARLA_PLUGIN->hints() & PLUGIN_USES_CHUNKS)
  101. {
  102. void* data = nullptr;
  103. int32_t dataSize = CARLA_PLUGIN->chunkData(&data);
  104. if (data && dataSize >= 4)
  105. {
  106. QString filePath;
  107. filePath += "/tmp/.CarlaChunk_";
  108. filePath += CARLA_PLUGIN->name();
  109. QFile file(filePath);
  110. if (file.open(QIODevice::WriteOnly))
  111. {
  112. QByteArray chunk((const char*)data, dataSize);
  113. file.write(chunk);
  114. file.close();
  115. osc_send_bridge_chunk_data(filePath.toUtf8().constData());
  116. }
  117. }
  118. }
  119. osc_send_configure(CARLA_BRIDGE_MSG_SAVED, "");
  120. #endif
  121. }
  122. void setCustomData(const char* const type, const char* const key, const char* const value)
  123. {
  124. Q_ASSERT(plugin);
  125. if (! plugin)
  126. return;
  127. plugin->setCustomData(CarlaBackend::getCustomDataStringType(type), key, value, true);
  128. }
  129. void setChunkData(const char* const filePath)
  130. {
  131. Q_ASSERT(plugin);
  132. if (! plugin)
  133. return;
  134. #if 0
  135. nextChunkFilePath = strdup(filePath);
  136. while (nextChunkFilePath)
  137. carla_msleep(25);
  138. #endif
  139. }
  140. // ---------------------------------------------------------------------
  141. // ...
  142. void handleCallback(const CarlaBackend::CallbackType action, const int value1, const int value2, const double value3)
  143. {
  144. switch (action)
  145. {
  146. case CarlaBackend::CALLBACK_PARAMETER_VALUE_CHANGED:
  147. //osc_send_control(value1, value3);
  148. break;
  149. case CarlaBackend::CALLBACK_PROGRAM_CHANGED:
  150. //osc_send_program(value1);
  151. break;
  152. case CarlaBackend::CALLBACK_MIDI_PROGRAM_CHANGED:
  153. //osc_send_midi_program(value1, value2, false);
  154. break;
  155. case CarlaBackend::CALLBACK_NOTE_ON:
  156. {
  157. //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_ON, (uint8_t)value1, (uint8_t)value2 };
  158. //osc_send_midi(mdata);
  159. break;
  160. }
  161. case CarlaBackend::CALLBACK_NOTE_OFF:
  162. {
  163. //uint8_t mdata[4] = { 0, MIDI_STATUS_NOTE_OFF, (uint8_t)value1, (uint8_t)value2 };
  164. //osc_send_midi(mdata);
  165. break;
  166. }
  167. case CarlaBackend::CALLBACK_SHOW_GUI:
  168. //if (value1 == 0)
  169. // osc_send_configure(CARLA_BRIDGE_MSG_HIDE_GUI, "");
  170. break;
  171. case CarlaBackend::CALLBACK_RESIZE_GUI:
  172. //if (client)
  173. // client->queque_message(BRIDGE_MESSAGE_RESIZE_GUI, value1, value2, 0.0);
  174. break;
  175. case CarlaBackend::CALLBACK_RELOAD_PARAMETERS:
  176. //if (CARLA_PLUGIN)
  177. //{
  178. // for (uint32_t i=0; i < CARLA_PLUGIN->parameterCount(); i++)
  179. // {
  180. // osc_send_control(i, CARLA_PLUGIN->getParameterValue(i));
  181. // }
  182. //}
  183. break;
  184. case CarlaBackend::CALLBACK_QUIT:
  185. quequeMessage(MESSAGE_QUIT, 0, 0, 0.0);
  186. break;
  187. }
  188. }
  189. // ---------------------------------------------------------------------
  190. static void callback(void* const ptr, CarlaBackend::CallbackType const action, const unsigned short, const int value1, const int value2, const double value3)
  191. {
  192. Q_ASSERT(ptr);
  193. if (! ptr)
  194. return;
  195. CarlaBridgePluginClient* const client = (CarlaBridgePluginClient*)ptr;
  196. client->handleCallback(action, value1, value2, value3);
  197. }
  198. private:
  199. CarlaBackend::CarlaEngine* engine;
  200. CarlaBackend::CarlaPlugin* plugin;
  201. };
  202. // -------------------------------------------------------------------------
  203. // toolkit
  204. class CarlaBridgeToolkitPlugin : public CarlaToolkit
  205. {
  206. public:
  207. CarlaBridgeToolkitPlugin(const char* const title)
  208. : CarlaToolkit(title)
  209. {
  210. qDebug("CarlaBridgeToolkitPlugin::CarlaBridgeToolkitPlugin(%s)", title);
  211. }
  212. ~CarlaBridgeToolkitPlugin()
  213. {
  214. qDebug("CarlaBridgeToolkitPlugin::~CarlaBridgeToolkitPlugin()");
  215. }
  216. void init()
  217. {
  218. }
  219. void exec(CarlaClient* const client)
  220. {
  221. m_client = client;
  222. }
  223. void quit()
  224. {
  225. }
  226. void show()
  227. {
  228. }
  229. void hide()
  230. {
  231. }
  232. void resize(int width, int height)
  233. {
  234. }
  235. };
  236. CarlaToolkit* CarlaToolkit::createNew(const char* const title)
  237. {
  238. return new CarlaBridgeToolkitPlugin(title);
  239. }
  240. CARLA_BRIDGE_END_NAMESPACE
  241. int main(int argc, char* argv[])
  242. {
  243. if (argc != 6)
  244. {
  245. qWarning("%s :: bad arguments", argv[0]);
  246. return 1;
  247. }
  248. const char* const oscUrl = argv[1];
  249. const char* const stype = argv[2];
  250. const char* const filename = argv[3];
  251. const char* name = argv[4];
  252. const char* const label = argv[5];
  253. if (strcmp(name, "(none)") == 0)
  254. name = nullptr;
  255. CarlaBackend::PluginType itype;
  256. if (strcmp(stype, "LADSPA") == 0)
  257. itype = CarlaBackend::PLUGIN_LADSPA;
  258. else if (strcmp(stype, "DSSI") == 0)
  259. itype = CarlaBackend::PLUGIN_DSSI;
  260. else if (strcmp(stype, "LV2") == 0)
  261. itype = CarlaBackend::PLUGIN_LV2;
  262. else if (strcmp(stype, "VST") == 0)
  263. itype = CarlaBackend::PLUGIN_VST;
  264. else
  265. {
  266. itype = CarlaBackend::PLUGIN_NONE;
  267. qWarning("Invalid plugin type '%s'", stype);
  268. return 1;
  269. }
  270. // Init toolkit
  271. CarlaBridge::CarlaBridgeToolkitPlugin toolkit(name);
  272. toolkit.init();
  273. // Init client
  274. CarlaBridge::CarlaBridgePluginClient client(&toolkit);
  275. // Init OSC
  276. if (! client.oscInit(oscUrl))
  277. {
  278. toolkit.quit();
  279. return -1;
  280. }
  281. // Init backend engine
  282. CarlaBackend::CarlaEngineJack engine;
  283. engine.setCallback(client.callback, &client);
  284. // bridge client <-> engine
  285. client.registerOscEngine(&engine);
  286. /// Init plugin
  287. short id = engine.addPlugin(itype, filename, name, label);
  288. if (id >= 0 && id < CarlaBackend::MAX_PLUGINS)
  289. {
  290. CarlaBackend::CarlaPlugin* const plugin = engine.getPlugin(id);
  291. client.setStuff(&engine, plugin);
  292. }
  293. else
  294. {
  295. qWarning("Plugin failed to load, error was:\n%s", CarlaBackend::getLastError());
  296. return 1;
  297. }
  298. // Init engine
  299. //QString engName = QString("%1 (master)").arg(label);
  300. //engName.truncate(CarlaEngine::maxClientNameSize());
  301. //CarlaEngine engine;
  302. //engine.init(engName.toUtf8().constData());
  303. // Init toolkit
  304. //toolkit_init();
  305. // Init plugin client
  306. //client = new PluginData;
  307. // Init OSC
  308. //osc_init(osc_url);
  309. //osc_send_update();
  310. toolkit.exec(&client);
  311. // Close OSC
  312. client.sendOscExiting();
  313. client.oscClose();
  314. // Close client
  315. //client.close();
  316. // Close toolkit
  317. toolkit.quit();
  318. return 0;
  319. }
  320. #if 0
  321. #define CARLA_PLUGIN CarlaBackend::CarlaPlugins[0]
  322. void toolkit_plugin_idle();
  323. ClientData* client = nullptr;
  324. // -------------------------------------------------------------------------
  325. // backend stuff
  326. // -------------------------------------------------------------------------
  327. // toolkit classes
  328. #ifdef __WINE__
  329. LRESULT WINAPI MainProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  330. {
  331. switch (msg)
  332. {
  333. case WM_CLOSE:
  334. if (client)
  335. client->queque_message(BRIDGE_MESSAGE_SHOW_GUI, 0, 0, 0.0);
  336. osc_send_configure(CARLA_BRIDGE_MSG_HIDE_GUI, "");
  337. return TRUE;
  338. }
  339. return DefWindowProc(hWnd, msg, wParam, lParam);
  340. }
  341. static bool close_now = false;
  342. static HINSTANCE hInst = nullptr;
  343. static HWND gui = nullptr;
  344. #else
  345. class PluginIdleTimer : public QTimer
  346. {
  347. public:
  348. PluginIdleTimer() {}
  349. void timerEvent(QTimerEvent*)
  350. {
  351. if (client)
  352. client->run_messages();
  353. toolkit_plugin_idle();
  354. }
  355. Q_SLOT void guiClosed()
  356. {
  357. //if (client)
  358. // client->queque_message(BRIDGE_MESSAGE_SHOW_GUI, 0, 0, 0.0);
  359. osc_send_configure(CARLA_BRIDGE_MSG_HIDE_GUI, "");
  360. }
  361. };
  362. static QApplication* app = nullptr;
  363. static QDialog* gui = nullptr;
  364. #endif
  365. #define nextShowMsgNULL 0
  366. #define nextShowMsgFALSE 1
  367. #define nextShowMsgTRUE 2
  368. static int nextShowMsg = nextShowMsgNULL;
  369. static const char* nextChunkFilePath = nullptr;
  370. // -------------------------------------------------------------------------
  371. // toolkit calls
  372. void toolkit_init()
  373. {
  374. #ifdef __WINE__
  375. #else
  376. static int argc = 0;
  377. static char* argv[] = { nullptr };
  378. app = new QApplication(argc, argv, true);
  379. #endif
  380. }
  381. void toolkit_plugin_idle()
  382. {
  383. if (nextShowMsg)
  384. {
  385. bool yesno = nextShowMsg - 1;
  386. CARLA_PLUGIN->showGui(yesno);
  387. if (gui)
  388. {
  389. #ifdef __WINE__
  390. ShowWindow(gui, yesno ? SW_SHOWNORMAL : SW_HIDE);
  391. UpdateWindow(gui);
  392. #else
  393. gui->setVisible(yesno);
  394. #endif
  395. }
  396. nextShowMsg = nextShowMsgNULL;
  397. }
  398. if (nextChunkFilePath)
  399. {
  400. QFile file(nextChunkFilePath);
  401. free((void*)nextChunkFilePath);
  402. nextChunkFilePath = nullptr;
  403. if (file.open(QIODevice::ReadOnly | QIODevice::Text))
  404. {
  405. QString stringData = file.readAll();
  406. file.remove();
  407. CARLA_PLUGIN->setChunkData(stringData.toUtf8().constData());
  408. }
  409. }
  410. CARLA_PLUGIN->idleGui();
  411. static PluginPostEvent postEvents[MAX_POST_EVENTS];
  412. CARLA_PLUGIN->postEventsCopy(postEvents);
  413. for (uint32_t i=0; i < MAX_POST_EVENTS; i++)
  414. {
  415. if (postEvents[i].type == PluginPostEventNull)
  416. break;
  417. switch (postEvents[i].type)
  418. {
  419. case PluginPostEventParameterChange:
  420. callback_action(CALLBACK_PARAMETER_CHANGED, 0, postEvents[i].index, 0, postEvents[i].value);
  421. break;
  422. case PluginPostEventProgramChange:
  423. callback_action(CALLBACK_PROGRAM_CHANGED, 0, postEvents[i].index, 0, 0.0);
  424. break;
  425. case PluginPostEventMidiProgramChange:
  426. callback_action(CALLBACK_MIDI_PROGRAM_CHANGED, 0, postEvents[i].index, 0, 0.0);
  427. break;
  428. case PluginPostEventNoteOn:
  429. callback_action(CALLBACK_NOTE_ON, 0, postEvents[i].index, postEvents[i].value, 0.0);
  430. break;
  431. case PluginPostEventNoteOff:
  432. callback_action(CALLBACK_NOTE_OFF, 0, postEvents[i].index, 0, 0.0);
  433. break;
  434. default:
  435. break;
  436. }
  437. }
  438. const ParameterData* paramData;
  439. for (uint32_t i=0; i < CARLA_PLUGIN->parameterCount(); i++)
  440. {
  441. paramData = CARLA_PLUGIN->parameterData(i);
  442. if (paramData->type == PARAMETER_OUTPUT && (paramData->hints & PARAMETER_IS_AUTOMABLE) > 0)
  443. osc_send_control(paramData->rindex, CARLA_PLUGIN->getParameterValue(i));
  444. }
  445. if (CARLA_PLUGIN->audioInCount() > 0)
  446. {
  447. osc_send_bridge_ains_peak(1, ains_peak[0]);
  448. osc_send_bridge_ains_peak(2, ains_peak[1]);
  449. }
  450. if (CARLA_PLUGIN->audioOutCount() > 0)
  451. {
  452. osc_send_bridge_aouts_peak(1, aouts_peak[0]);
  453. osc_send_bridge_aouts_peak(2, aouts_peak[1]);
  454. }
  455. }
  456. void toolkit_loop()
  457. {
  458. #ifdef __WINE__
  459. MSG msg;
  460. while (! close_now)
  461. {
  462. while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  463. DispatchMessage(&msg);
  464. client->run_messages();
  465. toolkit_plugin_idle();
  466. carla_msleep(50);
  467. }
  468. #else
  469. PluginIdleTimer timer;
  470. timer.start(50);
  471. if (gui)
  472. timer.connect(gui, SIGNAL(finished(int)), &timer, SLOT(guiClosed()));
  473. app->setQuitOnLastWindowClosed(false);
  474. app->exec();
  475. #endif
  476. }
  477. void toolkit_quit()
  478. {
  479. #ifdef __WINE__
  480. close_now = true;
  481. #else
  482. if (app)
  483. app->quit();
  484. #endif
  485. }
  486. void toolkit_window_show()
  487. {
  488. nextShowMsg = nextShowMsgTRUE;
  489. }
  490. void toolkit_window_hide()
  491. {
  492. nextShowMsg = nextShowMsgFALSE;
  493. }
  494. void toolkit_window_resize(int width, int height)
  495. {
  496. if (gui)
  497. {
  498. #ifdef __WINE__
  499. SetWindowPos(gui, 0, 0, 0, width + 6, height + 25, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  500. #else
  501. gui->setFixedSize(width, height);
  502. #endif
  503. }
  504. }
  505. // -------------------------------------------------------------------------
  506. // -------------------------------------------------------------------------
  507. #ifdef __WINE__
  508. int WINAPI WinMain(HINSTANCE hInstX, HINSTANCE, LPSTR, int)
  509. {
  510. hInst = hInstX;
  511. #define MAXCMDTOKENS 128
  512. int argc;
  513. LPSTR argv[MAXCMDTOKENS];
  514. LPSTR p = GetCommandLine();
  515. char command[256];
  516. char *args;
  517. char *d, *e;
  518. argc = 0;
  519. args = (char *)malloc(lstrlen(p)+1);
  520. if (args == (char *)NULL) {
  521. qCritical("Insufficient memory in WinMain()");
  522. return 1;
  523. }
  524. // Parse command line handling quotes.
  525. d = args;
  526. while (*p)
  527. {
  528. // for each argument
  529. if (argc >= MAXCMDTOKENS - 1)
  530. break;
  531. e = d;
  532. while ((*p) && (*p != ' ')) {
  533. if (*p == '\042') {
  534. // Remove quotes, skipping over embedded spaces.
  535. // Doesn't handle embedded quotes.
  536. p++;
  537. while ((*p) && (*p != '\042'))
  538. *d++ =*p++;
  539. }
  540. else
  541. *d++ = *p;
  542. if (*p)
  543. p++;
  544. }
  545. *d++ = '\0';
  546. argv[argc++] = e;
  547. while ((*p) && (*p == ' '))
  548. p++; // Skip over trailing spaces
  549. }
  550. argv[argc] = 0;
  551. if (strlen(argv[0]) == 0)
  552. {
  553. GetModuleFileName(hInst, command, sizeof(command)-1);
  554. argv[0] = command;
  555. }
  556. #else
  557. int main(int argc, char* argv[])
  558. {
  559. #endif
  560. if (argc != 6)
  561. {
  562. qWarning("%s :: bad arguments", argv[0]);
  563. return 1;
  564. }
  565. const char* const osc_url = argv[1];
  566. const char* const stype = argv[2];
  567. const char* const filename = argv[3];
  568. const char* name = argv[4];
  569. const char* const label = argv[5];
  570. if (strcmp(name, "(none)") == 0)
  571. name = nullptr;
  572. short id;
  573. PluginType itype;
  574. if (strcmp(stype, "LADSPA") == 0)
  575. itype = PLUGIN_LADSPA;
  576. else if (strcmp(stype, "DSSI") == 0)
  577. itype = PLUGIN_DSSI;
  578. else if (strcmp(stype, "LV2") == 0)
  579. itype = PLUGIN_LV2;
  580. else if (strcmp(stype, "VST") == 0)
  581. itype = PLUGIN_VST;
  582. else
  583. {
  584. itype = PLUGIN_NONE;
  585. qWarning("Invalid plugin type '%s'", stype);
  586. return 1;
  587. }
  588. // Init backend
  589. set_callback_function(plugin_bridge_callback);
  590. set_last_error("no error");
  591. // Init engine
  592. QString engName = QString("%1 (master)").arg(label);
  593. engName.truncate(CarlaEngine::maxClientNameSize());
  594. CarlaEngine engine;
  595. engine.init(engName.toUtf8().constData());
  596. // Init toolkit
  597. toolkit_init();
  598. // Init plugin client
  599. client = new PluginData;
  600. // Init OSC
  601. osc_init(osc_url);
  602. osc_send_update();
  603. // Get plugin type
  604. switch (itype)
  605. {
  606. case PLUGIN_LADSPA:
  607. id = add_plugin_ladspa(filename, name, label, nullptr);
  608. break;
  609. case PLUGIN_DSSI:
  610. id = add_plugin_dssi(filename, name, label, nullptr);
  611. break;
  612. case PLUGIN_LV2:
  613. id = add_plugin_lv2(filename, name, label);
  614. break;
  615. case PLUGIN_VST:
  616. id = add_plugin_vst(filename, name, label);
  617. break;
  618. default:
  619. id = -1;
  620. break;
  621. }
  622. // Init plugin
  623. if (id == 0 && CARLA_PLUGIN)
  624. {
  625. // Create gui if needed
  626. GuiInfo guiInfo;
  627. CARLA_PLUGIN->getGuiInfo(&guiInfo);
  628. QString guiTitle = QString("%1 (GUI)").arg(CARLA_PLUGIN->name());
  629. #ifdef __WINE__
  630. if (guiInfo.type == GUI_INTERNAL_HWND)
  631. {
  632. WNDCLASSEX wclass;
  633. wclass.cbSize = sizeof(WNDCLASSEX);
  634. wclass.style = 0;
  635. wclass.lpfnWndProc = MainProc;
  636. wclass.cbClsExtra = 0;
  637. wclass.cbWndExtra = 0;
  638. wclass.hInstance = hInst;
  639. wclass.hIcon = LoadIcon(hInst, "carla");
  640. wclass.hCursor = LoadCursor(0, IDI_APPLICATION);
  641. wclass.lpszMenuName = "MENU_CARLA_BRIDGE";
  642. wclass.lpszClassName = "CLASS_CARLA_BRIDGE";
  643. wclass.hIconSm = 0;
  644. if (! RegisterClassEx(&wclass))
  645. {
  646. qCritical("Failed to register Wine application");
  647. return 1;
  648. }
  649. gui = CreateWindow("CLASS_CARLA_BRIDGE", guiTitle.toUtf8().constData(),
  650. WS_OVERLAPPEDWINDOW & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX,
  651. CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  652. 0, 0, hInst, 0);
  653. SetWindowPos(gui, 0, 0, 0, 6, 25, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER);
  654. qDebug("Wine GUI created");
  655. #else
  656. if (guiInfo.type == GUI_INTERNAL_QT4 || guiInfo.type == GUI_INTERNAL_X11)
  657. {
  658. gui = new QDialog(nullptr);
  659. gui->resize(10, 10);
  660. gui->setWindowTitle(guiTitle);
  661. #endif
  662. CARLA_PLUGIN->setGuiData(0, gui);
  663. }
  664. // Report OK to backend
  665. osc_send_bridge_update();
  666. // Main loop
  667. toolkit_loop();
  668. // Remove & delete plugin
  669. carla_proc_lock();
  670. CARLA_PLUGIN->setEnabled(false);
  671. carla_proc_unlock();
  672. delete CARLA_PLUGIN;
  673. // Cleanup
  674. #ifndef __WINE__
  675. if (gui)
  676. {
  677. gui->close();
  678. delete gui;
  679. }
  680. delete app;
  681. #endif
  682. }
  683. else
  684. {
  685. qWarning("Plugin failed to load, error was:\n%s", get_last_error());
  686. return 1;
  687. }
  688. // delete old data
  689. if (nextChunkFilePath)
  690. {
  691. free((void*)nextChunkFilePath);
  692. nextChunkFilePath = nullptr;
  693. }
  694. // Close plugin client
  695. delete client;
  696. client = nullptr;
  697. // Close engine
  698. engine.close();
  699. // Close OSC
  700. osc_send_exiting();
  701. osc_close();
  702. return 0;
  703. }
  704. #endif