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.

209 lines
6.8KB

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