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.

307 lines
9.6KB

  1. /*
  2. * Carla Backend
  3. * Copyright (C) 2011-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. #include "carla_threads.hpp"
  18. #include "carla_plugin.hpp"
  19. #include <QtCore/QDebug>
  20. #include <QtCore/QProcess>
  21. // -----------------------------------------------------------------------
  22. // CarlaCheckThread
  23. CarlaCheckThread::CarlaCheckThread(CarlaBackend::CarlaEngine* const engine_, QObject* const parent)
  24. : QThread(parent),
  25. engine(engine_)
  26. {
  27. qDebug("CarlaCheckThread::CarlaCheckThread(%p, %p)", engine, parent);
  28. CARLA_ASSERT(engine);
  29. }
  30. CarlaCheckThread::~CarlaCheckThread()
  31. {
  32. qDebug("CarlaCheckThread::~CarlaCheckThread()");
  33. }
  34. void CarlaCheckThread::startNow()
  35. {
  36. qDebug("CarlaCheckThread::startNow()");
  37. start(QThread::HighPriority);
  38. }
  39. void CarlaCheckThread::stopNow()
  40. {
  41. if (m_stopNow)
  42. return;
  43. m_stopNow = true;
  44. // TESTING - let processing finish first
  45. QMutexLocker(&this->mutex); // FIXME
  46. if (isRunning() && ! wait(200))
  47. {
  48. quit();
  49. if (isRunning() && ! wait(300))
  50. terminate();
  51. }
  52. }
  53. void CarlaCheckThread::run()
  54. {
  55. qDebug("CarlaCheckThread::run()");
  56. using namespace CarlaBackend;
  57. bool oscControlRegisted, usesSingleThread;
  58. unsigned short id, maxPluginNumber = CarlaEngine::maxPluginNumber();
  59. double value;
  60. m_stopNow = false;
  61. while (engine->isRunning() && ! m_stopNow)
  62. {
  63. const ScopedLocker m(this);
  64. oscControlRegisted = engine->isOscControlRegisted();
  65. #ifndef BUILD_BRIDGE
  66. if (engine->getType() != CarlaEngineTypePlugin)
  67. engine->oscWaitEvents();
  68. #endif
  69. for (unsigned short i=0; i < maxPluginNumber; i++)
  70. {
  71. CarlaPlugin* const plugin = engine->getPluginUnchecked(i);
  72. if (plugin && plugin->enabled())
  73. {
  74. id = plugin->id();
  75. usesSingleThread = (plugin->hints() & PLUGIN_USES_SINGLE_THREAD);
  76. // -------------------------------------------------------
  77. // Process postponed events
  78. if (! usesSingleThread)
  79. plugin->postEventsRun();
  80. // -------------------------------------------------------
  81. // Update parameter outputs
  82. if (oscControlRegisted || ! usesSingleThread)
  83. {
  84. for (uint32_t i=0; i < plugin->parameterCount(); i++)
  85. {
  86. if (plugin->parameterIsOutput(i))
  87. {
  88. value = plugin->getParameterValue(i);
  89. // Update UI
  90. if (! usesSingleThread)
  91. plugin->uiParameterChange(i, value);
  92. // Update OSC control client
  93. if (oscControlRegisted)
  94. {
  95. #ifdef BUILD_BRIDGE
  96. engine->osc_send_bridge_set_parameter_value(i, value);
  97. #else
  98. engine->osc_send_control_set_parameter_value(id, i, value);
  99. #endif
  100. }
  101. }
  102. }
  103. }
  104. // -------------------------------------------------------
  105. // Update OSC control client
  106. if (oscControlRegisted)
  107. {
  108. // Peak values
  109. if (plugin->audioInCount() > 0)
  110. {
  111. #ifdef BUILD_BRIDGE
  112. engine->osc_send_bridge_set_inpeak(1, engine->getInputPeak(id, 0));
  113. engine->osc_send_bridge_set_inpeak(2, engine->getInputPeak(id, 1));
  114. #else
  115. engine->osc_send_control_set_input_peak_value(id, 1, engine->getInputPeak(id, 0));
  116. engine->osc_send_control_set_input_peak_value(id, 2, engine->getInputPeak(id, 1));
  117. #endif
  118. }
  119. if (plugin->audioOutCount() > 0)
  120. {
  121. #ifdef BUILD_BRIDGE
  122. engine->osc_send_bridge_set_outpeak(1, engine->getOutputPeak(id, 0));
  123. engine->osc_send_bridge_set_outpeak(2, engine->getOutputPeak(id, 1));
  124. #else
  125. engine->osc_send_control_set_output_peak_value(id, 1, engine->getOutputPeak(id, 0));
  126. engine->osc_send_control_set_output_peak_value(id, 2, engine->getOutputPeak(id, 1));
  127. #endif
  128. }
  129. }
  130. }
  131. }
  132. msleep(50);
  133. }
  134. }
  135. // -----------------------------------------------------------------------
  136. // CarlaPluginThread
  137. #ifndef BUILD_BRIDGE
  138. const char* PluginThreadMode2str(const CarlaPluginThread::PluginThreadMode mode)
  139. {
  140. switch (mode)
  141. {
  142. case CarlaPluginThread::PLUGIN_THREAD_DSSI_GUI:
  143. return "PLUGIN_THREAD_DSSI_GUI";
  144. case CarlaPluginThread::PLUGIN_THREAD_LV2_GUI:
  145. return "PLUGIN_THREAD_LV2_GUI";
  146. case CarlaPluginThread::PLUGIN_THREAD_VST_GUI:
  147. return "PLUGIN_THREAD_VST_GUI";
  148. case CarlaPluginThread::PLUGIN_THREAD_BRIDGE:
  149. return "PLUGIN_THREAD_BRIDGE";
  150. }
  151. qWarning("CarlaPluginThread::PluginThreadMode2str(%i) - invalid mode", mode);
  152. return nullptr;
  153. }
  154. CarlaPluginThread::CarlaPluginThread(CarlaBackend::CarlaEngine* const engine_, CarlaBackend::CarlaPlugin* const plugin_, const PluginThreadMode mode_, QObject* const parent)
  155. : QThread(parent),
  156. engine(engine_),
  157. plugin(plugin_),
  158. mode(mode_)
  159. {
  160. qDebug("CarlaPluginThread::CarlaPluginThread(plugin:\"%s\", engine:\"%s\", %s)", plugin->name(), engine->getName(), PluginThreadMode2str(mode));
  161. m_process = nullptr;
  162. }
  163. CarlaPluginThread::~CarlaPluginThread()
  164. {
  165. if (m_process)
  166. delete m_process;
  167. }
  168. void CarlaPluginThread::setOscData(const char* const binary, const char* const label, const char* const data1)
  169. {
  170. m_binary = QString(binary);
  171. m_label = QString(label);
  172. m_data1 = QString(data1);
  173. }
  174. void CarlaPluginThread::run()
  175. {
  176. qDebug("CarlaPluginThread::run()");
  177. if (! m_process)
  178. m_process = new QProcess(nullptr);
  179. m_process->setProcessChannelMode(QProcess::ForwardedChannels);
  180. QStringList arguments;
  181. const char* name = plugin->name() ? plugin->name() : "(none)";
  182. switch (mode)
  183. {
  184. case PLUGIN_THREAD_DSSI_GUI:
  185. /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathUDP()).arg(plugin->id());
  186. /* filename */ arguments << plugin->filename();
  187. /* label */ arguments << m_label;
  188. /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
  189. break;
  190. case PLUGIN_THREAD_LV2_GUI:
  191. /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
  192. /* URI */ arguments << m_label;
  193. /* ui-URI */ arguments << m_data1;
  194. /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
  195. break;
  196. case PLUGIN_THREAD_VST_GUI:
  197. /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
  198. /* filename */ arguments << plugin->filename();
  199. /* ui-title */ arguments << QString("%1 (GUI)").arg(plugin->name());
  200. break;
  201. case PLUGIN_THREAD_BRIDGE:
  202. /* osc_url */ arguments << QString("%1/%2").arg(engine->getOscServerPathTCP()).arg(plugin->id());
  203. /* stype */ arguments << m_data1;
  204. /* filename */ arguments << plugin->filename();
  205. /* name */ arguments << name;
  206. /* label */ arguments << m_label;
  207. break;
  208. }
  209. m_process->start(m_binary, arguments);
  210. m_process->waitForStarted();
  211. switch (mode)
  212. {
  213. case PLUGIN_THREAD_DSSI_GUI:
  214. case PLUGIN_THREAD_LV2_GUI:
  215. case PLUGIN_THREAD_VST_GUI:
  216. if (plugin->showOscGui())
  217. {
  218. m_process->waitForFinished(-1);
  219. if (m_process->exitCode() == 0)
  220. {
  221. // Hide
  222. engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0);
  223. qWarning("CarlaPluginThread::run() - GUI closed");
  224. }
  225. else
  226. {
  227. // Kill
  228. engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), -1, 0, 0.0);
  229. qWarning("CarlaPluginThread::run() - GUI crashed");
  230. break;
  231. }
  232. }
  233. else
  234. {
  235. qDebug("CarlaPluginThread::run() - GUI timeout");
  236. engine->callback(CarlaBackend::CALLBACK_SHOW_GUI, plugin->id(), 0, 0, 0.0);
  237. }
  238. break;
  239. case PLUGIN_THREAD_BRIDGE:
  240. m_process->waitForFinished(-1);
  241. if (m_process->exitCode() != 0)
  242. {
  243. qWarning("CarlaPluginThread::run() - bridge crashed");
  244. QString errorString = QString("Plugin '%1' has crashed!\n"
  245. "Saving now will lose its current settings.\n"
  246. "Please remove this plugin, and not rely on it from this point.").arg(plugin->name());
  247. CarlaBackend::setLastError(errorString.toUtf8().constData());
  248. engine->callback(CarlaBackend::CALLBACK_ERROR, plugin->id(), 0, 0, 0.0);
  249. }
  250. break;
  251. }
  252. }
  253. #endif