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.

214 lines
6.9KB

  1. /*
  2. * Carla Plugin Thread
  3. * Copyright (C) 2012-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 doc/GPL.txt file.
  16. */
  17. #include "CarlaPluginThread.hpp"
  18. #include "CarlaPlugin.hpp"
  19. #include "CarlaEngine.hpp"
  20. #include <QtCore/QProcess>
  21. CARLA_BACKEND_START_NAMESPACE
  22. const char* PluginThreadMode2str(const CarlaPluginThread::Mode mode)
  23. {
  24. switch (mode)
  25. {
  26. case CarlaPluginThread::PLUGIN_THREAD_NULL:
  27. return "PLUGIN_THREAD_NULL";
  28. case CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI:
  29. return "PLUGIN_THREAD_DSSI_GUI";
  30. case CarlaPluginThread::PLUGIN_THREAD_LV2_GUI:
  31. return "PLUGIN_THREAD_LV2_GUI";
  32. case CarlaPluginThread::PLUGIN_THREAD_VST_GUI:
  33. return "PLUGIN_THREAD_VST_GUI";
  34. case CarlaPluginThread::PLUGIN_THREAD_BRIDGE:
  35. return "PLUGIN_THREAD_BRIDGE";
  36. }
  37. carla_stderr("CarlaPluginThread::PluginThreadMode2str(%i) - invalid mode", mode);
  38. return nullptr;
  39. }
  40. CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine, CarlaBackend::CarlaPlugin* const plugin, const Mode mode)
  41. : fEngine(engine),
  42. fPlugin(plugin),
  43. fMode(mode),
  44. fProcess(nullptr)
  45. {
  46. carla_debug("CarlaPluginThread::CarlaPluginThread(plugin:\"%s\", engine:\"%s\", %s)", plugin->getName(), engine->getName(), PluginThreadMode2str(mode));
  47. }
  48. CarlaPluginThread::~CarlaPluginThread()
  49. {
  50. carla_debug("CarlaPluginThread::~CarlaPluginThread()");
  51. if (fProcess != nullptr)
  52. {
  53. delete fProcess;
  54. fProcess = nullptr;
  55. }
  56. }
  57. void CarlaPluginThread::setMode(const CarlaPluginThread::Mode mode) noexcept
  58. {
  59. fMode = mode;
  60. }
  61. void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const extra1, const char* const extra2)
  62. {
  63. fBinary = binary;
  64. fLabel = label;
  65. fExtra1 = extra1;
  66. fExtra2 = extra2;
  67. }
  68. void CarlaPluginThread::run()
  69. {
  70. carla_debug("CarlaPluginThread::run()");
  71. if (fProcess == nullptr)
  72. {
  73. fProcess = new QProcess(nullptr);
  74. fProcess->setProcessChannelMode(QProcess::ForwardedChannels);
  75. }
  76. else if (fProcess->state() == QProcess::Running)
  77. {
  78. carla_stderr("CarlaPluginThread::run() - already running, giving up...");
  79. switch (fMode)
  80. {
  81. case PLUGIN_THREAD_NULL:
  82. break;
  83. case PLUGIN_THREAD_DSSI_GUI:
  84. case PLUGIN_THREAD_LV2_GUI:
  85. case PLUGIN_THREAD_VST_GUI:
  86. fProcess->terminate();
  87. fEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, fPlugin->getId(), -1, 0, 0.0f, nullptr);
  88. return;
  89. case PLUGIN_THREAD_BRIDGE:
  90. break;
  91. }
  92. }
  93. QString name(fPlugin->getName());
  94. QStringList arguments;
  95. if (name.isEmpty())
  96. name = "(none)";
  97. switch (fMode)
  98. {
  99. case PLUGIN_THREAD_NULL:
  100. break;
  101. case PLUGIN_THREAD_DSSI_GUI:
  102. /* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathUDP()).arg(fPlugin->getId());
  103. /* filename */ arguments << fPlugin->getFilename();
  104. /* label */ arguments << (const char*)fLabel;
  105. /* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName());
  106. break;
  107. case PLUGIN_THREAD_LV2_GUI:
  108. /* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathTCP()).arg(fPlugin->getId());
  109. /* URI */ arguments << (const char*)fLabel;
  110. /* ui-URI */ arguments << (const char*)fExtra1;
  111. /* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName());
  112. break;
  113. case PLUGIN_THREAD_VST_GUI:
  114. /* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathTCP()).arg(fPlugin->getId());
  115. /* filename */ arguments << fPlugin->getFilename();
  116. /* ui-title */ arguments << QString("%1 (GUI)").arg(fPlugin->getName());
  117. break;
  118. case PLUGIN_THREAD_BRIDGE:
  119. /* osc-url */ arguments << QString("%1/%2").arg(fEngine->getOscServerPathTCP()).arg(fPlugin->getId());
  120. /* stype */ arguments << (const char*)fExtra1;
  121. /* filename */ arguments << fPlugin->getFilename();
  122. /* name */ arguments << name;
  123. /* label */ arguments << (const char*)fLabel;
  124. /* SHM ids */ arguments << (const char*)fExtra2;
  125. break;
  126. }
  127. fProcess->start((const char*)fBinary, arguments);
  128. fProcess->waitForStarted();
  129. switch (fMode)
  130. {
  131. case PLUGIN_THREAD_NULL:
  132. break;
  133. case PLUGIN_THREAD_DSSI_GUI:
  134. case PLUGIN_THREAD_LV2_GUI:
  135. case PLUGIN_THREAD_VST_GUI:
  136. if (fPlugin->waitForOscGuiShow())
  137. {
  138. fProcess->waitForFinished(-1);
  139. if (fProcess->exitCode() == 0)
  140. {
  141. // Hide
  142. fEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, fPlugin->getId(), 0, 0, 0.0f, nullptr);
  143. carla_stdout("CarlaPluginThread::run() - GUI closed");
  144. }
  145. else
  146. {
  147. // Kill
  148. fEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, fPlugin->getId(), -1, 0, 0.0f, nullptr);
  149. carla_stderr("CarlaPluginThread::run() - GUI crashed while running");
  150. }
  151. }
  152. else
  153. {
  154. fProcess->close();
  155. CARLA_ASSERT(fProcess->state() == QProcess::NotRunning);
  156. if (fProcess->exitCode() != 0 || fProcess->exitStatus() == QProcess::CrashExit)
  157. {
  158. fEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, fPlugin->getId(), -1, 0, 0.0f, nullptr);
  159. carla_stderr("CarlaPluginThread::run() - GUI crashed while opening");
  160. }
  161. else
  162. {
  163. fEngine->callback(CarlaBackend::CALLBACK_SHOW_GUI, fPlugin->getId(), 0, 0, 0.0f, nullptr);
  164. carla_debug("CarlaPluginThread::run() - GUI timeout");
  165. }
  166. }
  167. break;
  168. case PLUGIN_THREAD_BRIDGE:
  169. fProcess->waitForFinished(-1);
  170. if (fProcess->exitCode() != 0 || fProcess->exitStatus() == QProcess::CrashExit)
  171. {
  172. carla_stderr("CarlaPluginThread::run() - bridge crashed");
  173. CarlaString errorString("Plugin '" + CarlaString(fPlugin->getName()) + "' has crashed!\n"
  174. "Saving now will lose its current settings.\n"
  175. "Please remove this plugin, and not rely on it from this point.");
  176. fEngine->callback(CarlaBackend::CALLBACK_ERROR, fPlugin->getId(), 0, 0, 0.0f, (const char*)errorString);
  177. }
  178. break;
  179. }
  180. }
  181. CARLA_BACKEND_END_NAMESPACE